(Exchange) Add GetHistoricCandles() & GetHistoricCandlesEx() support to exchanges (#479)

* implemented binance and bitfinex GetHistoricCandles wrapper methods)

* coinbene supported added

* after and before clean up

* gateio wrapper completed

* merged upstream/master

* Added bsaic KlineIntervalSupported() method

* Converted binance fixed test

* WIP

* new KlineConvertToExchangeStandardString method added

* end of day WIP

* WIP

* end of day WIP started migration of trade history

* added kline support to hitbtc huobi lbank

* added exchangehistory to all supported exchanges started work on coinbase 300 candles/request method

* end of day WIP

* removed unused ta and misc changes to flag ready for review

* yobit cleanup

* revert coinbase changES

* general code clean up and added zb support

* poloniex support added

* renamed method to FormatExchangeKlineInterval other misc fixes

* linter fixes

* linter fixes

* removed verbose

* fixed poloniex test coverage

* revert poloniex mock data

* regenerated poloniex mock data

* a very verbose clean up

* binance mock clean up

* removed unneeded t.Log()

* setting verbose to true to debug CI issue

* first pass changes addressed

* common.ErrNotYetImplemented implemented :D

* comments added

* WIP-addressed exchange requests and reverted previous GetExchangeHistory changes

* WIP-addressed exchange requests and reverted previous GetExchangeHistory changes

* increased test coverage added kraken support

* OKGroup support completed started work on address GetExchangeHistory feedback and migrating to own PR under https://github.com/xtda/gocryptotrader/tree/exchange_history

* convert zb ratelimits

* gofmt run on okcoin

* increased delay on rate limit

* gofmt package

* fixed panic with coinbene and bithumb if conversion fails

* very broken end of day WIP

* added support for GetHistoricCandlesEx to coinbase and binance

* gofmt package

* coinbase, btcmarkets, zb ex wrapper function added

* added all exchange support for ex regenerated mock data

* update bithumb to return wrapper method

* gofmt package

* end of day started work on changes

* reworked test coverage added okgroup support general fixes/change requests addressed

* Added OneMonth

* limit checks on supportedexchanges

* reverted getexchangehistory

* reworked binance tesT

* added workaround for kraken panic

* renamed command to extended removed interval check on non-implemented commands

* added wrapperconfig back

* increased test coverage for FormatExchangeKlineInterval

* WIP

* increased test coverage for FormatExchangeKlineInterval bitfinex/gateio/huobi

* linter fixes

* zb kraken lbank coinbene btcmarkets support added

* removed verbose

* OK group support for other asset types added

* swapped margin to use spot endpoint

* index support added test coverage added for asset types

* added asset type to okcoin test

* gofmt

* add asset to extended method

* removed verbose

* add support for coinbene swap increase test coverage

* removed verbose

* small clean up of okgroup wrapper functions

* verbose to troubleshoot CI issues

* removed verbose

* added error check reverted coinbasechanges

* readme updated

* removed unused start/finish started work on decoupling api requests from kline package

* restructured coinbene, bithumb methods, added bitstamp support

* kraken time fix

* BTCMarkets restructure

* typo fix

* removed test for futures due to contact changing

* added start/end date to extended method over range

* converted to assettranslator

* removed verbose

* removed invalid char

* reverted incorrectly removed return

* added import

* further template updates

* macos hates my keyboard :D

* misc canges

* x -> i

* removed verbose

* updated fixCasing to allocate var before checks

* removed time conversion

* sort all outgoing kline candles

* fixCasing fix

* after/before checks added

* added parallel to test

* logic check on BTCmarkets

* removed unused param, used correct iterator

* converted HitBTC to use time.Time

* add iszero false check to candle times

* updated resultlimit to 5000

* new line added

* added comment to exported const

* use configured ratelimit

* fixed pair for test

* panic fixed WIP on fixCasing

* fixCasing rework, started work on readme docs

* enable rate limiter for wrapper issues tool

* docs updated

* removed err from return and formatted currency

* updated Yobit supported status

* Updated HitBTC to use onehour candles due to test exeuction times

* added further details to gctcli output

* added link to docs

* added link to tempalte

* disable FTX websocket in config_example

* fix poloneix

* regenerated poloniex mock data

* removed recording flag
This commit is contained in:
Andrew
2020-07-08 10:51:54 +10:00
committed by GitHub
parent c2c200cd1b
commit 4a736fb335
112 changed files with 52287 additions and 12550 deletions

View File

@@ -159,12 +159,6 @@ func (o *OKEX) GetFuturesFilledOrder(request okgroup.GetFuturesFilledOrderReques
return resp, o.SendHTTPRequest(http.MethodGet, okGroupFuturesSubsection, requestURL, nil, &resp, true)
}
// GetFuturesMarketData Get the charts of the trading pairs. Charts are returned in grouped buckets based on requested granularity.
func (o *OKEX) GetFuturesMarketData(request okgroup.GetFuturesMarketDateRequest) (resp okgroup.GetFuturesMarketDataResponse, _ error) {
requestURL := fmt.Sprintf("%v/%v/%v%v", okgroup.OKGroupInstruments, request.InstrumentID, okgroup.OKGroupGetSpotMarketData, okgroup.FormatParameters(request))
return resp, o.SendHTTPRequest(http.MethodGet, okGroupFuturesSubsection, requestURL, nil, &resp, true)
}
// GetFuturesHoldAmount Get the number of futures with hold.
func (o *OKEX) GetFuturesHoldAmount(instrumentID string) (resp okgroup.GetFuturesHoldAmountResponse, _ error) {
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupAccounts, instrumentID, okGroupFutureHolds)
@@ -327,12 +321,6 @@ func (o *OKEX) GetSwapFilledOrdersData(request *okgroup.GetSwapFilledOrdersDataR
return resp, o.SendHTTPRequest(http.MethodGet, okGroupSwapSubsection, requestURL, nil, &resp, false)
}
// GetSwapMarketData Get the charts of the trading pairs.
func (o *OKEX) GetSwapMarketData(request okgroup.GetSwapMarketDataRequest) (resp []okgroup.GetSwapMarketDataResponse, _ error) {
requestURL := fmt.Sprintf("%v/%v/%v%v", okgroup.OKGroupInstruments, request.InstrumentID, okgroup.OKGroupGetSpotMarketData, okgroup.FormatParameters(request))
return resp, o.SendHTTPRequest(http.MethodGet, okGroupSwapSubsection, requestURL, nil, &resp, false)
}
// GetSwapIndices Get Indices of tokens.
func (o *OKEX) GetSwapIndices(instrumentID string) (resp okgroup.GetSwapIndecesResponse, _ error) {
requestURL := fmt.Sprintf("%v/%v/%v", okgroup.OKGroupInstruments, instrumentID, okGroupIndices)

View File

@@ -19,6 +19,7 @@ import (
"github.com/thrasher-corp/gocryptotrader/currency"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
"github.com/thrasher-corp/gocryptotrader/exchanges/okgroup"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
@@ -519,16 +520,56 @@ func TestGetSpotFilledOrdersInformation(t *testing.T) {
// TestGetSpotMarketData API endpoint test
func TestGetSpotMarketData(t *testing.T) {
t.Parallel()
request := okgroup.GetSpotMarketDataRequest{
request := &okgroup.GetMarketDataRequest{
Asset: asset.Spot,
InstrumentID: spotCurrency,
Granularity: 604800,
Granularity: "604800",
}
_, err := o.GetSpotMarketData(request)
_, err := o.GetMarketData(request)
if err != nil {
t.Error(err)
}
}
func TestGetHistoricCandles(t *testing.T) {
currencyPair := currency.NewPairFromString("BTCUSDT")
startTime := time.Unix(1588636800, 0)
_, err := o.GetHistoricCandles(currencyPair, asset.Spot, startTime, time.Now(), kline.OneMin)
if err != nil {
t.Fatal(err)
}
_, err = o.GetHistoricCandles(currencyPair, asset.Spot, startTime, time.Now(), kline.Interval(time.Hour*7))
if err == nil {
t.Fatal("unexpected result")
}
_, err = o.GetHistoricCandles(currencyPair, asset.Margin, startTime, time.Now(), kline.Interval(time.Hour*7))
if err == nil {
t.Fatal("unexpected result")
}
swapPair := currency.NewPairFromString("BTC-USD_SWAP")
_, err = o.GetHistoricCandles(swapPair, asset.PerpetualSwap, startTime, time.Now(), kline.OneDay)
if err != nil {
t.Fatal(err)
}
}
func TestGetHistoricCandlesExtended(t *testing.T) {
currencyPair := currency.NewPairFromString("BTCUSDT")
startTime := time.Unix(1588636800, 0)
_, err := o.GetHistoricCandlesExtended(currencyPair, asset.Spot, startTime, time.Now(), kline.OneMin)
if err != nil {
t.Fatal(err)
}
_, err = o.GetHistoricCandles(currencyPair, asset.Spot, startTime, time.Now(), kline.Interval(time.Hour*7))
if err == nil {
t.Fatal("unexpected result")
}
}
// TestGetMarginTradingAccounts API endpoint test
func TestGetMarginTradingAccounts(t *testing.T) {
t.Parallel()
@@ -1240,19 +1281,6 @@ func TestGetSwapFilledOrdersData(t *testing.T) {
}
}
// TestGetSwapMarketData API endpoint test
func TestGetSwapMarketData(t *testing.T) {
t.Parallel()
request := okgroup.GetSwapMarketDataRequest{
InstrumentID: fmt.Sprintf("%v-%v-SWAP", currency.BTC, currency.USD),
Granularity: 604800,
}
_, err := o.GetSwapMarketData(request)
if err != nil {
t.Error(err)
}
}
// TestGetSwapIndeces API endpoint test
func TestGetSwapIndeces(t *testing.T) {
t.Parallel()

View File

@@ -8,11 +8,13 @@ import (
"time"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/convert"
"github.com/thrasher-corp/gocryptotrader/config"
"github.com/thrasher-corp/gocryptotrader/currency"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
"github.com/thrasher-corp/gocryptotrader/exchanges/okgroup"
"github.com/thrasher-corp/gocryptotrader/exchanges/protocol"
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
@@ -145,9 +147,31 @@ func (o *OKEX) SetDefaults() {
},
WithdrawPermissions: exchange.AutoWithdrawCrypto |
exchange.NoFiatWithdrawals,
Kline: kline.ExchangeCapabilitiesSupported{
DateRanges: true,
Intervals: true,
},
},
Enabled: exchange.FeaturesEnabled{
AutoPairUpdates: true,
Kline: kline.ExchangeCapabilitiesEnabled{
Intervals: map[string]bool{
kline.OneMin.Word(): true,
kline.ThreeMin.Word(): true,
kline.FiveMin.Word(): true,
kline.FifteenMin.Word(): true,
kline.ThirtyMin.Word(): true,
kline.OneHour.Word(): true,
kline.TwoHour.Word(): true,
kline.FourHour.Word(): true,
kline.SixHour.Word(): true,
kline.TwelveHour.Word(): true,
kline.OneDay.Word(): true,
kline.ThreeDay.Word(): true,
kline.OneWeek.Word(): true,
},
ResultLimit: 1440,
},
},
}
@@ -419,6 +443,142 @@ func (o *OKEX) FetchTicker(p currency.Pair, assetType asset.Item) (tickerData *t
}
// GetHistoricCandles returns candles between a time period for a set time interval
func (o *OKEX) GetHistoricCandles(pair currency.Pair, a asset.Item, start, end time.Time, interval time.Duration) (kline.Item, error) {
return kline.Item{}, common.ErrFunctionNotSupported
func (o *OKEX) GetHistoricCandles(pair currency.Pair, a asset.Item, start, end time.Time, interval kline.Interval) (kline.Item, error) {
if !o.KlineIntervalEnabled(interval) {
return kline.Item{}, kline.ErrorKline{
Interval: interval,
}
}
req := &okgroup.GetMarketDataRequest{
Asset: a,
Start: start.UTC().Format(time.RFC3339),
End: end.UTC().Format(time.RFC3339),
Granularity: o.FormatExchangeKlineInterval(interval),
InstrumentID: o.FormatExchangeCurrency(pair, a).String(),
}
candles, err := o.GetMarketData(req)
if err != nil {
return kline.Item{}, err
}
ret := kline.Item{
Exchange: o.Name,
Pair: pair,
Asset: a,
Interval: interval,
}
for x := range candles {
t := candles[x].([]interface{})
tempCandle := kline.Candle{}
v, ok := t[0].(string)
if !ok {
return kline.Item{}, errors.New("unexpected value received")
}
tempCandle.Time, err = time.Parse(time.RFC3339, v)
if err != nil {
return kline.Item{}, err
}
tempCandle.Open, err = convert.FloatFromString(t[1])
if err != nil {
return kline.Item{}, err
}
tempCandle.High, err = convert.FloatFromString(t[2])
if err != nil {
return kline.Item{}, err
}
tempCandle.Low, err = convert.FloatFromString(t[3])
if err != nil {
return kline.Item{}, err
}
tempCandle.Close, err = convert.FloatFromString(t[4])
if err != nil {
return kline.Item{}, err
}
tempCandle.Volume, err = convert.FloatFromString(t[5])
if err != nil {
return kline.Item{}, err
}
ret.Candles = append(ret.Candles, tempCandle)
}
ret.SortCandlesByTimestamp(false)
return ret, nil
}
// GetHistoricCandlesExtended returns candles between a time period for a set time interval
func (o *OKEX) GetHistoricCandlesExtended(pair currency.Pair, a asset.Item, start, end time.Time, interval kline.Interval) (kline.Item, error) {
if !o.KlineIntervalEnabled(interval) {
return kline.Item{}, kline.ErrorKline{
Interval: interval,
}
}
ret := kline.Item{
Exchange: o.Name,
Pair: pair,
Asset: a,
Interval: interval,
}
dates := kline.CalcDateRanges(start, end, interval, o.Features.Enabled.Kline.ResultLimit)
for x := range dates {
req := &okgroup.GetMarketDataRequest{
Asset: a,
Start: dates[x].Start.UTC().Format(time.RFC3339),
End: dates[x].End.UTC().Format(time.RFC3339),
Granularity: o.FormatExchangeKlineInterval(interval),
InstrumentID: o.FormatExchangeCurrency(pair, a).String(),
}
candles, err := o.GetMarketData(req)
if err != nil {
return kline.Item{}, err
}
for i := range candles {
t := candles[i].([]interface{})
tempCandle := kline.Candle{}
v, ok := t[0].(string)
if !ok {
return kline.Item{}, errors.New("unexpected value received")
}
tempCandle.Time, err = time.Parse(time.RFC3339, v)
if err != nil {
return kline.Item{}, err
}
tempCandle.Open, err = convert.FloatFromString(t[1])
if err != nil {
return kline.Item{}, err
}
tempCandle.High, err = convert.FloatFromString(t[2])
if err != nil {
return kline.Item{}, err
}
tempCandle.Low, err = convert.FloatFromString(t[3])
if err != nil {
return kline.Item{}, err
}
tempCandle.Close, err = convert.FloatFromString(t[4])
if err != nil {
return kline.Item{}, err
}
tempCandle.Volume, err = convert.FloatFromString(t[5])
if err != nil {
return kline.Item{}, err
}
ret.Candles = append(ret.Candles, tempCandle)
}
}
ret.SortCandlesByTimestamp(false)
return ret, nil
}