(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

@@ -54,6 +54,7 @@ const (
bitstampAPIXrpDeposit = "xrp_address"
bitstampAPIReturnType = "string"
bitstampAPITradingPairsInfo = "trading-pairs-info"
bitstampOHLC = "ohlc"
bitstampRateInterval = time.Minute * 10
bitstampRequestRate = 8000
@@ -579,6 +580,24 @@ func (b *Bitstamp) GetUnconfirmedBitcoinDeposits() ([]UnconfirmedBTCTransactions
b.SendAuthenticatedHTTPRequest(bitstampAPIUnconfirmedBitcoin, false, nil, &response)
}
// OHLC returns OHLCV data for step (interval)
func (b *Bitstamp) OHLC(currency string, start, end time.Time, step, limit string) (resp OHLCResponse, err error) {
var v = url.Values{}
v.Add("limit", limit)
v.Add("step", step)
if start.After(end) && !end.IsZero() {
return resp, errors.New("start time cannot be after end time")
}
if !start.IsZero() {
v.Add("start", strconv.FormatInt(start.Unix(), 10))
}
if !end.IsZero() {
v.Add("end", strconv.FormatInt(end.Unix(), 10))
}
return resp, b.SendHTTPRequest(common.EncodeURLValues(b.API.Endpoints.URL+"/v"+bitstampAPIVersion+"/"+bitstampOHLC+"/"+currency, v), &resp)
}
// TransferAccountBalance transfers funds from either a main or sub account
// amount - to transfers
// currency - which currency to transfer

View File

@@ -3,10 +3,13 @@ package bitstamp
import (
"net/url"
"testing"
"time"
"github.com/thrasher-corp/gocryptotrader/core"
"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/order"
"github.com/thrasher-corp/gocryptotrader/portfolio/banking"
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
@@ -664,3 +667,33 @@ func TestWsRequestReconnect(t *testing.T) {
t.Error(err)
}
}
func TestBitstamp_OHLC(t *testing.T) {
start := time.Unix(1546300800, 0)
end := time.Unix(1577836799, 0)
_, err := b.OHLC("btcusd", start, end, "60", "10")
if err != nil {
t.Fatal(err)
}
}
func TestBitstamp_GetHistoricCandles(t *testing.T) {
currencyPair := currency.NewPairFromString("btcusd")
start := time.Unix(1546300800, 0)
end := time.Unix(1577836799, 0)
_, err := b.GetHistoricCandles(currencyPair, asset.Spot, start, end, kline.OneDay)
if err != nil {
t.Fatal(err)
}
}
func TestBitstamp_GetHistoricCandlesExtended(t *testing.T) {
currencyPair := currency.NewPairFromString("btcusd")
start := time.Unix(1546300800, 0)
end := time.Unix(1577836799, 0)
_, err := b.GetHistoricCandlesExtended(currencyPair, asset.Spot, start, end, kline.OneDay)
if err != nil {
t.Fatal(err)
}
}

View File

@@ -219,3 +219,18 @@ type websocketOrderBook struct {
Timestamp int64 `json:"timestamp,string"`
Microtimestamp string `json:"microtimestamp"`
}
// OHLCResponse holds returned candle data
type OHLCResponse struct {
Data struct {
Pair string `json:"pair"`
OHLCV []struct {
Timestamp int64 `json:"timestamp,string"`
Open float64 `json:"open,string"`
High float64 `json:"high,string"`
Low float64 `json:"low,string"`
Close float64 `json:"close,string"`
Volume float64 `json:"volume,string"`
} `json:"ohlc"`
} `json:"data"`
}

View File

@@ -103,9 +103,30 @@ func (b *Bitstamp) SetDefaults() {
},
WithdrawPermissions: exchange.AutoWithdrawCrypto |
exchange.AutoWithdrawFiat,
Kline: kline.ExchangeCapabilitiesSupported{
Intervals: true,
DateRanges: 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,
},
ResultLimit: 1000,
},
},
}
@@ -677,6 +698,95 @@ func (b *Bitstamp) ValidateCredentials() error {
}
// GetHistoricCandles returns candles between a time period for a set time interval
func (b *Bitstamp) GetHistoricCandles(pair currency.Pair, a asset.Item, start, end time.Time, interval time.Duration) (kline.Item, error) {
return kline.Item{}, common.ErrNotYetImplemented
func (b *Bitstamp) GetHistoricCandles(pair currency.Pair, a asset.Item, start, end time.Time, interval kline.Interval) (kline.Item, error) {
if !b.KlineIntervalEnabled(interval) {
return kline.Item{}, kline.ErrorKline{
Interval: interval,
}
}
ret := kline.Item{
Exchange: b.Name,
Pair: pair,
Asset: a,
Interval: interval,
}
candles, err := b.OHLC(
b.FormatExchangeCurrency(pair, a).Lower().String(),
start,
end,
b.FormatExchangeKlineInterval(interval),
strconv.FormatInt(int64(b.Features.Enabled.Kline.ResultLimit), 10),
)
if err != nil {
return kline.Item{}, err
}
for x := range candles.Data.OHLCV {
if time.Unix(candles.Data.OHLCV[x].Timestamp, 0).Before(start) ||
time.Unix(candles.Data.OHLCV[x].Timestamp, 0).After(end) {
continue
}
ret.Candles = append(ret.Candles, kline.Candle{
Time: time.Unix(candles.Data.OHLCV[x].Timestamp, 0),
Open: candles.Data.OHLCV[x].Open,
High: candles.Data.OHLCV[x].High,
Low: candles.Data.OHLCV[x].Low,
Close: candles.Data.OHLCV[x].Close,
Volume: candles.Data.OHLCV[x].Volume,
})
}
ret.SortCandlesByTimestamp(false)
return ret, nil
}
// GetHistoricCandlesExtended returns candles between a time period for a set time interval
func (b *Bitstamp) GetHistoricCandlesExtended(pair currency.Pair, a asset.Item, start, end time.Time, interval kline.Interval) (kline.Item, error) {
if !b.KlineIntervalEnabled(interval) {
return kline.Item{}, kline.ErrorKline{
Interval: interval,
}
}
ret := kline.Item{
Exchange: b.Name,
Pair: pair,
Asset: a,
Interval: interval,
}
dates := kline.CalcDateRanges(start, end, interval, b.Features.Enabled.Kline.ResultLimit)
for x := range dates {
candles, err := b.OHLC(
b.FormatExchangeCurrency(pair, a).Lower().String(),
dates[x].Start,
dates[x].End,
b.FormatExchangeKlineInterval(interval),
strconv.FormatInt(int64(b.Features.Enabled.Kline.ResultLimit), 10),
)
if err != nil {
return kline.Item{}, err
}
for i := range candles.Data.OHLCV {
if time.Unix(candles.Data.OHLCV[i].Timestamp, 0).Before(start) ||
time.Unix(candles.Data.OHLCV[i].Timestamp, 0).After(end) {
continue
}
ret.Candles = append(ret.Candles, kline.Candle{
Time: time.Unix(candles.Data.OHLCV[i].Timestamp, 0),
Open: candles.Data.OHLCV[i].Open,
High: candles.Data.OHLCV[i].High,
Low: candles.Data.OHLCV[i].Low,
Close: candles.Data.OHLCV[i].Close,
Volume: candles.Data.OHLCV[i].Volume,
})
}
}
ret.SortCandlesByTimestamp(false)
return ret, nil
}