This commit is contained in:
Adrian Gallagher
2019-09-02 18:05:49 +10:00
93 changed files with 1616 additions and 1067 deletions

View File

@@ -1211,18 +1211,18 @@
"apiUrlSecondary": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API",
"proxyAddress": "",
"websocketUrl": "NON_DEFAULT_HTTP_LINK_TO_WEBSOCKET_EXCHANGE_API",
"availablePairs": "BTC_USD,LTC_USD,ETH_USD,ETC_USD,TUSD_USD,USDT_USD,ZEC_USD,ADA_USD,XLM_USD,ZRX_USD,XRP_USD,BAT_USD,PAX_USD,GUSD_USD,USDC_USD,BCH_USD,BSV_USD,TRX_USD,GRIN_USD,DCR_USD,EOS_USD,BTC_TUSD,BTC_USDT,BTC_PAX,BTC_GUSD,BTC_USDC",
"enabledPairs": "BTC_USD",
"availablePairs": "BTC-USD,LTC-USD,ETH-USD,ETC-USD,TUSD-USD,USDT-USD,ZEC-USD,ADA-USD,XLM-USD,ZRX-USD,XRP-USD,BAT-USD,PAX-USD,GUSD-USD,USDC-USD,BCH-USD,BSV-USD,TRX-USD,GRIN-USD,DCR-USD,EOS-USD,BTC-TUSD,BTC-USDT,BTC-PAX,BTC-GUSD,BTC-USDC",
"enabledPairs": "BTC-USD",
"baseCurrencies": "USD",
"assetTypes": "SPOT",
"supportsAutoPairUpdates": true,
"configCurrencyPairFormat": {
"uppercase": true,
"delimiter": "_"
"delimiter": "-"
},
"requestCurrencyPairFormat": {
"uppercase": false,
"delimiter": "_"
"uppercase": true,
"delimiter": "-"
},
"bankAccounts": [
{
@@ -1256,18 +1256,18 @@
"apiUrlSecondary": "NON_DEFAULT_HTTP_LINK_TO_EXCHANGE_API",
"proxyAddress": "",
"websocketUrl": "NON_DEFAULT_HTTP_LINK_TO_WEBSOCKET_EXCHANGE_API",
"availablePairs": "DASH_BTC,CTXC_BTC,ZIL_BTC,YOU_BTC,LBA_BTC,LSK_BTC,CAI_BTC,AE_BTC,SC_BTC,KAN_BTC,WIN_BTC,DCR_BTC,WAVES_BTC,ORS_BTC,NXT_BTC,ARDR_BTC,XAS_BTC,CVT_BTC,EGT_BTC,ZCO_BTC,LET_BTC,HPB_BTC,ADA_BTC,HYC_BTC,VITE_BTC,ABL_BTC,PAX_BTC,TUSD_BTC,USDC_BTC,GUSD_BTC,BCH_BTC,BSV_BTC,BTT_BTC,ATOM_BTC,BLOC_BTC,XRP_BTC,LRC_BTC,NULS_BTC,MCO_BTC,ELF_BTC,ZEC_BTC,CMT_BTC,ITC_BTC,SBTC_BTC,EDO_BTC,BCX_BTC,NEO_BTC,GAS_BTC,HC_BTC,QTUM_BTC,IOTA_BTC,XUC_BTC,EOS_BTC,SNT_BTC,OMG_BTC,LTC_BTC,ETH_BTC,ETC_BTC,BCD_BTC,BTG_BTC,ACT_BTC,PAY_BTC,BTM_BTC,DGD_BTC,GNT_BTC,LINK_BTC,WTC_BTC,ZRX_BTC,BNT_BTC,CVC_BTC,MANA_BTC,KNC_BTC,GNX_BTC,ICX_BTC,XEM_BTC,ARK_BTC,YOYO_BTC,FUN_BTC,ACE_BTC,TRX_BTC,DGB_BTC,SWFTC_BTC,XMR_BTC,XLM_BTC,KCASH_BTC,MDT_BTC,NAS_BTC,UGC_BTC,DPY_BTC,SSC_BTC,AAC_BTC,VIB_BTC,QUN_BTC,INT_BTC,IOST_BTC,INS_BTC,MOF_BTC,TCT_BTC,STC_BTC,THETA_BTC,PST_BTC,SNC_BTC,MKR_BTC,LIGHT_BTC,TRUE_BTC,OF_BTC,SOC_BTC,ZEN_BTC,HMC_BTC,ZIP_BTC,NANO_BTC,CIC_BTC,GTO_BTC,CHAT_BTC,INSUR_BTC,R_BTC,BEC_BTC,MITH_BTC,ABT_BTC,BKX_BTC,RFR_BTC,TRIO_BTC,DADI_BTC,ONT_BTC,OKB_BTC,CTXC_ETH,ZIL_ETH,YOU_ETH,LBA_ETH,LSK_ETH,CAI_ETH,SC_ETH,AE_ETH,KAN_ETH,WIN_ETH,DCR_ETH,WAVES_ETH,ORS_ETH,MVP_ETH,EGT_ETH,ZCO_ETH,LET_ETH,HPB_ETH,SDA_ETH,ADA_ETH,HYC_ETH,VITE_ETH,ABL_ETH,BTT_ETH,ATOM_ETH,ELF_ETH,LTC_ETH,CMT_ETH,ITC_ETH,PRA_ETH,EDO_ETH,LRC_ETH,NULS_ETH,MCO_ETH,STORJ_ETH,SNT_ETH,PAY_ETH,DGD_ETH,GNT_ETH,ACT_ETH,BTM_ETH,EOS_ETH,OMG_ETH,DASH_ETH,XRP_ETH,ZEC_ETH,NEO_ETH,GAS_ETH,HC_ETH,QTUM_ETH,IOTA_ETH,XUC_ETH,ETC_ETH,LINK_ETH,WTC_ETH,ZRX_ETH,BNT_ETH,CVC_ETH,MANA_ETH,GNX_ETH,ICX_ETH,XEM_ETH,ARK_ETH,YOYO_ETH,TRX_ETH,DGB_ETH,PPT_ETH,SWFTC_ETH,XMR_ETH,XLM_ETH,KCASH_ETH,MDT_ETH,NAS_ETH,RNT_ETH,UGC_ETH,DPY_ETH,SSC_ETH,AAC_ETH,FAIR_ETH,RCT_ETH,VIB_ETH,TOPC_ETH,QUN_ETH,INT_ETH,IOST_ETH,INS_ETH,MOF_ETH,REF_ETH,THETA_ETH,PST_ETH,SNC_ETH,MKR_ETH,LIGHT_ETH,TRUE_ETH,OF_ETH,SOC_ETH,ZEN_ETH,HMC_ETH,ZIP_ETH,NANO_ETH,CIC_ETH,GTO_ETH,INSUR_ETH,R_ETH,UCT_ETH,BEC_ETH,MITH_ETH,ABT_ETH,BKX_ETH,AUTO_ETH,RFR_ETH,TRIO_ETH,TRA_ETH,DADI_ETH,ONT_ETH,OKB_ETH,CTXC_USDT,ZIL_USDT,YOU_OKB,YOU_USDT,LBA_OKB,LBA_USDT,CAI_OKB,LSK_USDT,CAI_USDT,AE_OKB,SC_OKB,KAN_OKB,WIN_OKB,SC_USDT,AE_USDT,KAN_USDT,WIN_USDT,ORS_OKB,DCR_OKB,DCR_USDT,WAVES_OKB,WAVES_USDT,ORS_USDT,MVP_USDT,NAS_OKB,XAS_OKB,ZCO_OKB,EGT_OKB,XAS_USDT,CVT_USDT,EGT_USDT,LET_OKB,LET_USDT,HPB_OKB,HPB_USDT,SDA_OKB,ADA_OKB,ADA_USDT,HYC_USDT,VITE_OKB,TRX_OKB,PAX_USDT,TUSD_USDT,USDC_USDT,GUSD_USDT,BCH_USDT,BSV_USDT,BTT_USDT,BLOC_OKB,BLOC_USDT,ATOM_USDT,ELF_USDT,DASH_USDT,LRC_USDT,NULS_USDT,MCO_USDT,BTG_USDT,DASH_OKB,XRP_USDT,ZEC_USDT,NEO_USDT,GAS_USDT,HC_USDT,QTUM_USDT,IOTA_USDT,BTC_USDT,BCD_USDT,XUC_USDT,CMT_USDT,ITC_USDT,PRA_USDT,EDO_USDT,ETH_USDT,LTC_USDT,ETC_USDT,EOS_USDT,OMG_USDT,ACT_USDT,BTM_USDT,STORJ_USDT,PAY_USDT,DGD_USDT,GNT_USDT,SNT_USDT,LINK_USDT,WTC_USDT,ZRX_USDT,BNT_USDT,CVC_USDT,MANA_USDT,KNC_USDT,ICX_USDT,XEM_USDT,ARK_USDT,YOYO_USDT,AST_USDT,TRX_USDT,MDA_USDT,DGB_USDT,PPT_USDT,SWFTC_USDT,XMR_USDT,XLM_USDT,KCASH_USDT,MDT_USDT,NAS_USDT,RNT_USDT,UGC_USDT,DPY_USDT,SSC_USDT,AAC_USDT,FAIR_USDT,UBTC_USDT,SHOW_USDT,VIB_USDT,MOT_USDT,UTK_USDT,TOPC_USDT,QUN_USDT,INT_USDT,IPC_USDT,IOST_USDT,INS_USDT,YEE_USDT,MOF_USDT,TCT_USDT,STC_USDT,THETA_USDT,PST_USDT,MKR_USDT,LIGHT_USDT,TRUE_USDT,OF_USDT,SOC_USDT,ZEN_USDT,HMC_USDT,ZIP_USDT,NANO_USDT,CIC_USDT,GTO_USDT,CHAT_USDT,INSUR_USDT,R_USDT,BEC_USDT,MITH_USDT,ABT_USDT,BKX_USDT,RFR_USDT,TRIO_USDT,DADI_USDT,ONT_USDT,OKB_USDT,NEO_OKB,LTC_OKB,ETC_OKB,XRP_OKB,ZEC_OKB,QTUM_OKB,IOTA_OKB,EOS_OKB",
"enabledPairs": "eos_usdt",
"availablePairs": "DASH-BTC,CTXC-BTC,ZIL-BTC,YOU-BTC,LBA-BTC,LSK-BTC,CAI-BTC,AE-BTC,SC-BTC,KAN-BTC,WIN-BTC,DCR-BTC,WAVES-BTC,ORS-BTC,NXT-BTC,ARDR-BTC,XAS-BTC,CVT-BTC,EGT-BTC,ZCO-BTC,LET-BTC,HPB-BTC,ADA-BTC,HYC-BTC,VITE-BTC,ABL-BTC,PAX-BTC,TUSD-BTC,USDC-BTC,GUSD-BTC,BCH-BTC,BSV-BTC,BTT-BTC,ATOM-BTC,BLOC-BTC,XRP-BTC,LRC-BTC,NULS-BTC,MCO-BTC,ELF-BTC,ZEC-BTC,CMT-BTC,ITC-BTC,SBTC-BTC,EDO-BTC,BCX-BTC,NEO-BTC,GAS-BTC,HC-BTC,QTUM-BTC,IOTA-BTC,XUC-BTC,EOS-BTC,SNT-BTC,OMG-BTC,LTC-BTC,ETH-BTC,ETC-BTC,BCD-BTC,BTG-BTC,ACT-BTC,PAY-BTC,BTM-BTC,DGD-BTC,GNT-BTC,LINK-BTC,WTC-BTC,ZRX-BTC,BNT-BTC,CVC-BTC,MANA-BTC,KNC-BTC,GNX-BTC,ICX-BTC,XEM-BTC,ARK-BTC,YOYO-BTC,FUN-BTC,ACE-BTC,TRX-BTC,DGB-BTC,SWFTC-BTC,XMR-BTC,XLM-BTC,KCASH-BTC,MDT-BTC,NAS-BTC,UGC-BTC,DPY-BTC,SSC-BTC,AAC-BTC,VIB-BTC,QUN-BTC,INT-BTC,IOST-BTC,INS-BTC,MOF-BTC,TCT-BTC,STC-BTC,THETA-BTC,PST-BTC,SNC-BTC,MKR-BTC,LIGHT-BTC,TRUE-BTC,OF-BTC,SOC-BTC,ZEN-BTC,HMC-BTC,ZIP-BTC,NANO-BTC,CIC-BTC,GTO-BTC,CHAT-BTC,INSUR-BTC,R-BTC,BEC-BTC,MITH-BTC,ABT-BTC,BKX-BTC,RFR-BTC,TRIO-BTC,DADI-BTC,ONT-BTC,OKB-BTC,CTXC-ETH,ZIL-ETH,YOU-ETH,LBA-ETH,LSK-ETH,CAI-ETH,SC-ETH,AE-ETH,KAN-ETH,WIN-ETH,DCR-ETH,WAVES-ETH,ORS-ETH,MVP-ETH,EGT-ETH,ZCO-ETH,LET-ETH,HPB-ETH,SDA-ETH,ADA-ETH,HYC-ETH,VITE-ETH,ABL-ETH,BTT-ETH,ATOM-ETH,ELF-ETH,LTC-ETH,CMT-ETH,ITC-ETH,PRA-ETH,EDO-ETH,LRC-ETH,NULS-ETH,MCO-ETH,STORJ-ETH,SNT-ETH,PAY-ETH,DGD-ETH,GNT-ETH,ACT-ETH,BTM-ETH,EOS-ETH,OMG-ETH,DASH-ETH,XRP-ETH,ZEC-ETH,NEO-ETH,GAS-ETH,HC-ETH,QTUM-ETH,IOTA-ETH,XUC-ETH,ETC-ETH,LINK-ETH,WTC-ETH,ZRX-ETH,BNT-ETH,CVC-ETH,MANA-ETH,GNX-ETH,ICX-ETH,XEM-ETH,ARK-ETH,YOYO-ETH,TRX-ETH,DGB-ETH,PPT-ETH,SWFTC-ETH,XMR-ETH,XLM-ETH,KCASH-ETH,MDT-ETH,NAS-ETH,RNT-ETH,UGC-ETH,DPY-ETH,SSC-ETH,AAC-ETH,FAIR-ETH,RCT-ETH,VIB-ETH,TOPC-ETH,QUN-ETH,INT-ETH,IOST-ETH,INS-ETH,MOF-ETH,REF-ETH,THETA-ETH,PST-ETH,SNC-ETH,MKR-ETH,LIGHT-ETH,TRUE-ETH,OF-ETH,SOC-ETH,ZEN-ETH,HMC-ETH,ZIP-ETH,NANO-ETH,CIC-ETH,GTO-ETH,INSUR-ETH,R-ETH,UCT-ETH,BEC-ETH,MITH-ETH,ABT-ETH,BKX-ETH,AUTO-ETH,RFR-ETH,TRIO-ETH,TRA-ETH,DADI-ETH,ONT-ETH,OKB-ETH,CTXC-USDT,ZIL-USDT,YOU-OKB,YOU-USDT,LBA-OKB,LBA-USDT,CAI-OKB,LSK-USDT,CAI-USDT,AE-OKB,SC-OKB,KAN-OKB,WIN-OKB,SC-USDT,AE-USDT,KAN-USDT,WIN-USDT,ORS-OKB,DCR-OKB,DCR-USDT,WAVES-OKB,WAVES-USDT,ORS-USDT,MVP-USDT,NAS-OKB,XAS-OKB,ZCO-OKB,EGT-OKB,XAS-USDT,CVT-USDT,EGT-USDT,LET-OKB,LET-USDT,HPB-OKB,HPB-USDT,SDA-OKB,ADA-OKB,ADA-USDT,HYC-USDT,VITE-OKB,TRX-OKB,PAX-USDT,TUSD-USDT,USDC-USDT,GUSD-USDT,BCH-USDT,BSV-USDT,BTT-USDT,BLOC-OKB,BLOC-USDT,ATOM-USDT,ELF-USDT,DASH-USDT,LRC-USDT,NULS-USDT,MCO-USDT,BTG-USDT,DASH-OKB,XRP-USDT,ZEC-USDT,NEO-USDT,GAS-USDT,HC-USDT,QTUM-USDT,IOTA-USDT,BTC-USDT,BCD-USDT,XUC-USDT,CMT-USDT,ITC-USDT,PRA-USDT,EDO-USDT,ETH-USDT,LTC-USDT,ETC-USDT,EOS-USDT,OMG-USDT,ACT-USDT,BTM-USDT,STORJ-USDT,PAY-USDT,DGD-USDT,GNT-USDT,SNT-USDT,LINK-USDT,WTC-USDT,ZRX-USDT,BNT-USDT,CVC-USDT,MANA-USDT,KNC-USDT,ICX-USDT,XEM-USDT,ARK-USDT,YOYO-USDT,AST-USDT,TRX-USDT,MDA-USDT,DGB-USDT,PPT-USDT,SWFTC-USDT,XMR-USDT,XLM-USDT,KCASH-USDT,MDT-USDT,NAS-USDT,RNT-USDT,UGC-USDT,DPY-USDT,SSC-USDT,AAC-USDT,FAIR-USDT,UBTC-USDT,SHOW-USDT,VIB-USDT,MOT-USDT,UTK-USDT,TOPC-USDT,QUN-USDT,INT-USDT,IPC-USDT,IOST-USDT,INS-USDT,YEE-USDT,MOF-USDT,TCT-USDT,STC-USDT,THETA-USDT,PST-USDT,MKR-USDT,LIGHT-USDT,TRUE-USDT,OF-USDT,SOC-USDT,ZEN-USDT,HMC-USDT,ZIP-USDT,NANO-USDT,CIC-USDT,GTO-USDT,CHAT-USDT,INSUR-USDT,R-USDT,BEC-USDT,MITH-USDT,ABT-USDT,BKX-USDT,RFR-USDT,TRIO-USDT,DADI-USDT,ONT-USDT,OKB-USDT,NEO-OKB,LTC-OKB,ETC-OKB,XRP-OKB,ZEC-OKB,QTUM-OKB,IOTA-OKB,EOS-OKB",
"enabledPairs": "EOS-USDT",
"baseCurrencies": "USD",
"assetTypes": "SPOT",
"supportsAutoPairUpdates": true,
"configCurrencyPairFormat": {
"uppercase": true,
"delimiter": "_"
"delimiter": "-"
},
"requestCurrencyPairFormat": {
"uppercase": false,
"delimiter": "_"
"uppercase": true,
"delimiter": "-"
},
"bankAccounts": [
{

View File

@@ -62,7 +62,7 @@ func NewPairFromIndex(currencyPair, index string) (Pair, error) {
// NewPairFromString converts currency string into a new CurrencyPair
// with or without delimeter
func NewPairFromString(currencyPair string) Pair {
delimiters := []string{"_", "-", "/"}
delimiters := []string{"_", "-", "/", ":"}
var delimiter string
for _, x := range delimiters {
if strings.Contains(currencyPair, x) {

View File

@@ -428,18 +428,27 @@ func WebsocketDataHandler(ws *wshandler.Websocket) {
// }
tickerNew := ticker.Price{
Last: d.Last,
High: d.High,
Low: d.Low,
Bid: d.Bid,
Ask: d.Ask,
Volume: d.Volume,
QuoteVolume: d.QuoteVolume,
PriceATH: d.PriceATH,
Open: d.Open,
Close: d.Close,
Pair: d.Pair,
LastUpdated: d.Timestamp,
Last: d.ClosePrice,
High: d.HighPrice,
Low: d.LowPrice,
Volume: d.Quantity,
}
if Bot.Settings.EnableExchangeSyncManager && Bot.ExchangeCurrencyPairManager != nil {
Bot.ExchangeCurrencyPairManager.update(ws.GetName(),
d.Pair, d.AssetType, SyncItemTicker, nil)
}
ticker.ProcessTicker(ws.GetName(), &tickerNew, d.AssetType)
err := ticker.ProcessTicker(ws.GetName(), &tickerNew, d.AssetType)
if err != nil {
log.Errorf(log.WebsocketMgr, "routines.go exchange %s websocket error - %s", ws.GetName(), err)
}
printTickerSummary(&tickerNew, tickerNew.Pair, d.AssetType, ws.GetName(), nil)
case wshandler.KlineData:
// Kline data

View File

@@ -486,6 +486,8 @@ func (e *ExchangeCurrencyPairSyncer) Start() {
} else {
usingWebsocket = true
}
} else {
usingWebsocket = true
}
} else if supportsREST {
usingREST = true

View File

@@ -161,16 +161,16 @@ type TickerComponent struct {
type Ticker struct {
Result string `json:"result"`
Data struct {
High TickerComponent `json:"high"`
Low TickerComponent `json:"low"`
Avg TickerComponent `json:"avg"`
Vwap TickerComponent `json:"vwap"`
Vol TickerComponent `json:"vol"`
Last TickerComponent `json:"last"`
Buy TickerComponent `json:"buy"`
Sell TickerComponent `json:"sell"`
Now string `json:"now"`
UpdateTime string `json:"dataUpdateTime"`
High TickerComponent `json:"high"`
Low TickerComponent `json:"low"`
Average TickerComponent `json:"avg"`
VolumeWeightedAveragePrice TickerComponent `json:"vwap"`
Volume TickerComponent `json:"vol"`
Last TickerComponent `json:"last"`
Buy TickerComponent `json:"buy"`
Sell TickerComponent `json:"sell"`
Now int64 `json:"now,string"`
UpdateTime int64 `json:"dataUpdateTime,string"`
} `json:"data"`
}

View File

@@ -2,12 +2,12 @@ package anx
import (
"fmt"
"strconv"
"strings"
"sync"
"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"
@@ -173,7 +173,7 @@ func (a *ANX) FetchTradablePairs(asset asset.Item) ([]string, error) {
var currencies []string
for x := range result.CurrencyPairs {
currencies = append(currencies, result.CurrencyPairs[x].TradedCcy+"_"+result.CurrencyPairs[x].SettlementCcy)
currencies = append(currencies, fmt.Sprintf("%v%v%v", result.CurrencyPairs[x].TradedCcy, a.GetPairFormat(asset, false).Delimiter, result.CurrencyPairs[x].SettlementCcy))
}
return currencies, nil
@@ -186,61 +186,22 @@ func (a *ANX) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Price,
if err != nil {
return tickerPrice, err
}
last, _ := convert.FloatFromString(tick.Data.Last.Value)
high, _ := convert.FloatFromString(tick.Data.High.Value)
low, _ := convert.FloatFromString(tick.Data.Low.Value)
bid, _ := convert.FloatFromString(tick.Data.Buy.Value)
ask, _ := convert.FloatFromString(tick.Data.Sell.Value)
volume, _ := convert.FloatFromString(tick.Data.Volume.Value)
tickerPrice.Pair = p
if tick.Data.Sell.Value != "" {
tickerPrice.Ask, err = strconv.ParseFloat(tick.Data.Sell.Value, 64)
if err != nil {
return tickerPrice, err
}
} else {
tickerPrice.Ask = 0
}
if tick.Data.Buy.Value != "" {
tickerPrice.Bid, err = strconv.ParseFloat(tick.Data.Buy.Value, 64)
if err != nil {
return tickerPrice, err
}
} else {
tickerPrice.Bid = 0
}
if tick.Data.Low.Value != "" {
tickerPrice.Low, err = strconv.ParseFloat(tick.Data.Low.Value, 64)
if err != nil {
return tickerPrice, err
}
} else {
tickerPrice.Low = 0
}
if tick.Data.Last.Value != "" {
tickerPrice.Last, err = strconv.ParseFloat(tick.Data.Last.Value, 64)
if err != nil {
return tickerPrice, err
}
} else {
tickerPrice.Last = 0
}
if tick.Data.Vol.Value != "" {
tickerPrice.Volume, err = strconv.ParseFloat(tick.Data.Vol.Value, 64)
if err != nil {
return tickerPrice, err
}
} else {
tickerPrice.Volume = 0
}
if tick.Data.High.Value != "" {
tickerPrice.High, err = strconv.ParseFloat(tick.Data.High.Value, 64)
if err != nil {
return tickerPrice, err
}
} else {
tickerPrice.High = 0
tickerPrice = ticker.Price{
Last: last,
High: high,
Low: low,
Bid: bid,
Ask: ask,
Volume: volume,
Pair: p,
LastUpdated: time.Unix(0, tick.Data.UpdateTime),
}
err = ticker.ProcessTicker(a.GetName(), &tickerPrice, assetType)

View File

@@ -167,29 +167,29 @@ type KlineStream struct {
// TickerStream holds the ticker stream data
type TickerStream struct {
EventType string `json:"e"`
EventTime int64 `json:"E"`
Symbol string `json:"s"`
PriceChange string `json:"p"`
PriceChangePercent string `json:"P"`
WeightedAvgPrice string `json:"w"`
PrevDayClose string `json:"x"`
CurrDayClose string `json:"c"`
CloseTradeQuantity string `json:"Q"`
BestBidPrice string `json:"b"`
BestBidQuantity string `json:"B"`
BestAskPrice string `json:"a"`
BestAskQuantity string `json:"A"`
OpenPrice string `json:"o"`
HighPrice string `json:"h"`
LowPrice string `json:"l"`
TotalTradedVolume string `json:"v"`
TotalTradedQuoteVolume string `json:"q"`
OpenTime int64 `json:"O"`
CloseTime int64 `json:"C"`
FirstTradeID int64 `json:"F"`
LastTradeID int64 `json:"L"`
NumberOfTrades int64 `json:"n"`
EventType string `json:"e"`
EventTime int64 `json:"E"`
Symbol currency.Pair `json:"s"`
PriceChange float64 `json:"p,string"`
PriceChangePercent float64 `json:"P,string"`
WeightedAvgPrice float64 `json:"w,string"`
ClosePrice float64 `json:"x,string"`
LastPrice float64 `json:"c,string"`
LastPriceQuantity float64 `json:"Q,string"`
BestBidPrice float64 `json:"b,string"`
BestBidQuantity float64 `json:"B,string"`
BestAskPrice float64 `json:"a,string"`
BestAskQuantity float64 `json:"A,string"`
OpenPrice float64 `json:"o,string"`
HighPrice float64 `json:"h,string"`
LowPrice float64 `json:"l,string"`
TotalTradedVolume float64 `json:"v,string"`
TotalTradedQuoteVolume float64 `json:"q,string"`
OpenTime int64 `json:"O"`
CloseTime int64 `json:"C"`
FirstTradeID int64 `json:"F"`
LastTradeID int64 `json:"L"`
NumberOfTrades int64 `json:"n"`
}
// HistoricalTrade holds recent trade data
@@ -239,25 +239,25 @@ type AveragePrice struct {
// PriceChangeStats contains statistics for the last 24 hours trade
type PriceChangeStats struct {
Symbol string `json:"symbol"`
PriceChange float64 `json:"priceChange,string"`
PriceChangePercent float64 `json:"priceChangePercent,string"`
WeightedAvgPrice float64 `json:"weightedAvgPrice,string"`
PrevClosePrice float64 `json:"prevClosePrice,string"`
LastPrice float64 `json:"lastPrice,string"`
LastQty float64 `json:"lastQty,string"`
BidPrice float64 `json:"bidPrice,string"`
AskPrice float64 `json:"askPrice,string"`
OpenPrice float64 `json:"openPrice,string"`
HighPrice float64 `json:"highPrice,string"`
LowPrice float64 `json:"lowPrice,string"`
Volume float64 `json:"volume,string"`
QuoteVolume float64 `json:"quoteVolume,string"`
OpenTime int64 `json:"openTime"`
CloseTime int64 `json:"closeTime"`
FirstID int64 `json:"fristId"`
LastID int64 `json:"lastId"`
Count int64 `json:"count"`
Symbol currency.Pair `json:"symbol"`
PriceChange float64 `json:"priceChange,string"`
PriceChangePercent float64 `json:"priceChangePercent,string"`
WeightedAvgPrice float64 `json:"weightedAvgPrice,string"`
PrevClosePrice float64 `json:"prevClosePrice,string"`
LastPrice float64 `json:"lastPrice,string"`
LastQty float64 `json:"lastQty,string"`
BidPrice float64 `json:"bidPrice,string"`
AskPrice float64 `json:"askPrice,string"`
OpenPrice float64 `json:"openPrice,string"`
HighPrice float64 `json:"highPrice,string"`
LowPrice float64 `json:"lowPrice,string"`
Volume float64 `json:"volume,string"`
QuoteVolume float64 `json:"quoteVolume,string"`
OpenTime int64 `json:"openTime"`
CloseTime int64 `json:"closeTime"`
FirstID int64 `json:"fristId"`
LastID int64 `json:"lastId"`
Count int64 `json:"count"`
}
// SymbolPrice holds basic symbol price

View File

@@ -147,18 +147,21 @@ func (b *Binance) WsHandleData() {
continue
}
var wsTicker wshandler.TickerData
wsTicker.Timestamp = time.Unix(t.EventTime/1000, 0)
wsTicker.Pair = currency.NewPairFromString(t.Symbol)
wsTicker.AssetType = asset.Spot
wsTicker.Exchange = b.GetName()
wsTicker.ClosePrice, _ = strconv.ParseFloat(t.CurrDayClose, 64)
wsTicker.Quantity, _ = strconv.ParseFloat(t.TotalTradedVolume, 64)
wsTicker.OpenPrice, _ = strconv.ParseFloat(t.OpenPrice, 64)
wsTicker.HighPrice, _ = strconv.ParseFloat(t.HighPrice, 64)
wsTicker.LowPrice, _ = strconv.ParseFloat(t.LowPrice, 64)
b.Websocket.DataHandler <- wsTicker
b.Websocket.DataHandler <- wshandler.TickerData{
Exchange: b.Name,
Open: t.OpenPrice,
Close: t.ClosePrice,
Volume: t.TotalTradedVolume,
QuoteVolume: t.TotalTradedQuoteVolume,
High: t.HighPrice,
Low: t.LowPrice,
Bid: t.BestBidPrice,
Ask: t.BestAskPrice,
Last: t.LastPrice,
Timestamp: time.Unix(0, t.EventTime),
AssetType: asset.Spot,
Pair: t.Symbol,
}
continue
case "kline":

View File

@@ -163,9 +163,9 @@ func (b *Binance) Run() {
}
forceUpdate := false
if !common.StringDataContains(b.GetEnabledPairs(asset.Spot).Strings(), "-") ||
!common.StringDataContains(b.GetAvailablePairs(asset.Spot).Strings(), "-") {
enabledPairs := currency.NewPairsFromStrings([]string{"BTC-USDT"})
if !common.StringDataContains(b.GetEnabledPairs(asset.Spot).Strings(), b.GetPairFormat(asset.Spot, false).Delimiter) ||
!common.StringDataContains(b.GetAvailablePairs(asset.Spot).Strings(), b.GetPairFormat(asset.Spot, false).Delimiter) {
enabledPairs := currency.NewPairsFromStrings([]string{fmt.Sprintf("BTC%vUSDT", b.GetPairFormat(asset.Spot, false).Delimiter)})
log.Warn(log.ExchangeSys,
"Available pairs for Binance reset due to config upgrade, please enable the ones you would like again")
forceUpdate = true
@@ -197,8 +197,10 @@ func (b *Binance) FetchTradablePairs(asset asset.Item) ([]string, error) {
for x := range info.Symbols {
if info.Symbols[x].Status == "TRADING" {
validCurrencyPairs = append(validCurrencyPairs,
info.Symbols[x].BaseAsset+"-"+info.Symbols[x].QuoteAsset)
validCurrencyPairs = append(validCurrencyPairs, fmt.Sprintf("%v%v%v",
info.Symbols[x].BaseAsset,
b.GetPairFormat(asset, false).Delimiter,
info.Symbols[x].QuoteAsset))
}
}
return validCurrencyPairs, nil
@@ -222,21 +224,28 @@ func (b *Binance) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Pr
if err != nil {
return tickerPrice, err
}
for _, x := range b.GetEnabledPairs(assetType) {
curr := b.FormatExchangeCurrency(x, assetType)
pairs := b.GetEnabledPairs(assetType)
for i := range pairs {
for y := range tick {
if tick[y].Symbol != curr.String() {
if !tick[y].Symbol.Equal(pairs[i]) {
continue
}
tickerPrice.Pair = x
tickerPrice.Ask = tick[y].AskPrice
tickerPrice.Bid = tick[y].BidPrice
tickerPrice.High = tick[y].HighPrice
tickerPrice.Last = tick[y].LastPrice
tickerPrice.Low = tick[y].LowPrice
tickerPrice.Volume = tick[y].Volume
ticker.ProcessTicker(b.Name, &tickerPrice, assetType)
tickerPrice := ticker.Price{
Last: tick[y].LastPrice,
High: tick[y].HighPrice,
Low: tick[y].LowPrice,
Bid: tick[y].BidPrice,
Ask: tick[y].AskPrice,
Volume: tick[y].Volume,
QuoteVolume: tick[y].QuoteVolume,
Open: tick[y].OpenPrice,
Close: tick[y].PrevClosePrice,
Pair: pairs[i],
}
err = ticker.ProcessTicker(b.Name, &tickerPrice, assetType)
if err != nil {
log.Error(log.Ticker, err)
}
}
}
return ticker.GetTicker(b.Name, p, assetType)

View File

@@ -48,6 +48,20 @@ func TestSetup(t *testing.T) {
b.Requester.SetRateLimit(false, time.Millisecond*300, 1)
}
func TestAppendOptionalDelimiter(t *testing.T) {
curr1 := currency.NewPairFromString("BTCUSD")
b.appendOptionalDelimiter(&curr1)
if curr1.Delimiter != "" {
t.Errorf("Expected no delimiter, received %v", curr1.Delimiter)
}
curr2 := currency.NewPairFromString("DUSK:USD")
curr2.Delimiter = ""
b.appendOptionalDelimiter(&curr2)
if curr2.Delimiter != ":" {
t.Errorf("Expected \"-\" as a delimiter, received %v", curr2.Delimiter)
}
}
func TestGetPlatformStatus(t *testing.T) {
t.Parallel()

View File

@@ -1,5 +1,7 @@
package bitfinex
import "time"
// Ticker holds basic ticker information from the exchange
type Ticker struct {
Mid float64 `json:"mid,string"`
@@ -28,6 +30,7 @@ type Tickerv2 struct {
Volume float64
High float64
Low float64
Timestamp time.Time
}
// Tickersv2 holds the version 2 tickers information

View File

@@ -271,13 +271,15 @@ func (b *Bitfinex) WsDataHandler() {
}
case "ticker":
b.Websocket.DataHandler <- wshandler.TickerData{
Quantity: chanData[8].(float64),
ClosePrice: chanData[7].(float64),
HighPrice: chanData[9].(float64),
LowPrice: chanData[10].(float64),
Pair: currency.NewPairFromString(chanInfo.Pair),
Exchange: b.GetName(),
AssetType: asset.Spot,
Exchange: b.Name,
Volume: chanData[8].(float64),
High: chanData[9].(float64),
Low: chanData[10].(float64),
Bid: chanData[1].(float64),
Ask: chanData[3].(float64),
Last: chanData[7].(float64),
AssetType: asset.Spot,
Pair: currency.NewPairFromString(chanInfo.Pair),
}
case "account":
@@ -539,6 +541,7 @@ func (b *Bitfinex) GenerateDefaultSubscriptions() {
for i := range channels {
enabledPairs := b.GetEnabledPairs(asset.Spot)
for j := range enabledPairs {
b.appendOptionalDelimiter(&enabledPairs[j])
params := make(map[string]interface{})
if channels[i] == "book" {
params["prec"] = "P0"

View File

@@ -194,40 +194,39 @@ func (b *Bitfinex) UpdateTradablePairs(forceUpdate bool) error {
func (b *Bitfinex) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Price, error) {
var tickerPrice ticker.Price
enabledPairs := b.GetEnabledPairs(assetType)
var pairs []string
for x := range enabledPairs {
b.appendOptionalDelimiter(&enabledPairs[x])
pairs = append(pairs, "t"+enabledPairs[x].String())
}
tickerNew, err := b.GetTickersV2(strings.Join(pairs, ","))
if err != nil {
return tickerPrice, err
}
for x := range tickerNew {
newP := currency.NewPairFromStrings(tickerNew[x].Symbol[1:4],
tickerNew[x].Symbol[4:])
var tick ticker.Price
tick.Pair = newP
tick.Ask = tickerNew[x].Ask
tick.Bid = tickerNew[x].Bid
tick.Low = tickerNew[x].Low
tick.Last = tickerNew[x].Last
tick.Volume = tickerNew[x].Volume
tick.High = tickerNew[x].High
for i := range tickerNew {
newP := tickerNew[i].Symbol[1:] // Remove the "t" prefix
tick := ticker.Price{
Last: tickerNew[i].Last,
High: tickerNew[i].High,
Low: tickerNew[i].Low,
Bid: tickerNew[i].Bid,
Ask: tickerNew[i].Ask,
Volume: tickerNew[i].Volume,
Pair: currency.NewPairFromString(newP),
LastUpdated: tickerNew[i].Timestamp,
}
err = ticker.ProcessTicker(b.Name, &tick, assetType)
if err != nil {
return tickerPrice, err
log.Error(log.Ticker, err)
}
}
return ticker.GetTicker(b.Name, p, assetType)
}
// FetchTicker returns the ticker for a currency pair
func (b *Bitfinex) FetchTicker(p currency.Pair, assetType asset.Item) (ticker.Price, error) {
b.appendOptionalDelimiter(&p)
tick, err := ticker.GetTicker(b.GetName(), p, asset.Spot)
if err != nil {
return b.UpdateTicker(p, assetType)
@@ -237,6 +236,7 @@ func (b *Bitfinex) FetchTicker(p currency.Pair, assetType asset.Item) (ticker.Pr
// FetchOrderbook returns the orderbook for a currency pair
func (b *Bitfinex) FetchOrderbook(p currency.Pair, assetType asset.Item) (orderbook.Base, error) {
b.appendOptionalDelimiter(&p)
ob, err := orderbook.Get(b.GetName(), p, assetType)
if err != nil {
return b.UpdateOrderbook(p, assetType)
@@ -246,6 +246,7 @@ func (b *Bitfinex) FetchOrderbook(p currency.Pair, assetType asset.Item) (orderb
// UpdateOrderbook updates and returns the orderbook for a currency pair
func (b *Bitfinex) UpdateOrderbook(p currency.Pair, assetType asset.Item) (orderbook.Base, error) {
b.appendOptionalDelimiter(&p)
var orderBook orderbook.Base
urlVals := url.Values{}
urlVals.Set("limit_bids", "100")
@@ -339,7 +340,7 @@ func (b *Bitfinex) SubmitOrder(order *exchange.OrderSubmission) (exchange.Submit
if order.OrderSide == exchange.BuyOrderSide {
isBuying = true
}
b.appendOptionalDelimiter(&order.Pair)
response, err := b.NewOrder(order.Pair.String(),
order.Amount,
order.Price,
@@ -592,6 +593,9 @@ func (b *Bitfinex) GetOrderHistory(getOrdersRequest *exchange.GetOrdersRequest)
exchange.FilterOrdersBySide(&orders, getOrdersRequest.OrderSide)
exchange.FilterOrdersByType(&orders, getOrdersRequest.OrderType)
exchange.FilterOrdersByTickRange(&orders, getOrdersRequest.StartTicks, getOrdersRequest.EndTicks)
for i := range getOrdersRequest.Currencies {
b.appendOptionalDelimiter(&getOrdersRequest.Currencies[i])
}
exchange.FilterOrdersByCurrencies(&orders, getOrdersRequest.Currencies)
return orders, nil
}
@@ -599,6 +603,9 @@ func (b *Bitfinex) GetOrderHistory(getOrdersRequest *exchange.GetOrdersRequest)
// SubscribeToWebsocketChannels appends to ChannelsToSubscribe
// which lets websocket.manageSubscriptions handle subscribing
func (b *Bitfinex) SubscribeToWebsocketChannels(channels []wshandler.WebsocketChannelSubscription) error {
for i := range channels {
b.appendOptionalDelimiter(&channels[i].Currency)
}
b.Websocket.SubscribeToChannels(channels)
return nil
}
@@ -606,6 +613,9 @@ func (b *Bitfinex) SubscribeToWebsocketChannels(channels []wshandler.WebsocketCh
// UnsubscribeToWebsocketChannels removes from ChannelsToSubscribe
// which lets websocket.manageSubscriptions handle unsubscribing
func (b *Bitfinex) UnsubscribeToWebsocketChannels(channels []wshandler.WebsocketChannelSubscription) error {
for i := range channels {
b.appendOptionalDelimiter(&channels[i].Currency)
}
b.Websocket.RemoveSubscribedChannels(channels)
return nil
}
@@ -619,3 +629,11 @@ func (b *Bitfinex) GetSubscriptions() ([]wshandler.WebsocketChannelSubscription,
func (b *Bitfinex) AuthenticateWebsocket() error {
return b.WsSendAuth()
}
// appendOptionalDelimiter ensures that a delimiter is present for long character currencies
func (b *Bitfinex) appendOptionalDelimiter(p *currency.Pair) {
if len(p.Quote.String()) > 3 ||
len(p.Base.String()) > 3 {
p.Delimiter = ":"
}
}

View File

@@ -138,7 +138,7 @@ func (b *Bitflyer) FetchTradablePairs(assetType asset.Item) ([]string, error) {
for _, info := range pairs {
if info.Alias != "" && assetType == asset.Futures {
products = append(products, info.Alias)
} else if info.Alias == "" && assetType == asset.Spot && strings.Contains(info.ProductCode, "_") {
} else if info.Alias == "" && assetType == asset.Spot && strings.Contains(info.ProductCode, b.GetPairFormat(assetType, false).Delimiter) {
products = append(products, info.ProductCode)
}
}
@@ -177,10 +177,8 @@ func (b *Bitflyer) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.P
tickerPrice.Pair = p
tickerPrice.Ask = tickerNew.BestAsk
tickerPrice.Bid = tickerNew.BestBid
// tickerPrice.Low
tickerPrice.Last = tickerNew.Last
tickerPrice.Volume = tickerNew.Volume
// tickerPrice.High
err = ticker.ProcessTicker(b.GetName(), &tickerPrice, assetType)
if err != nil {
return tickerPrice, err

View File

@@ -154,24 +154,27 @@ func (b *Bithumb) UpdateTradablePairs(forceUpdate bool) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (b *Bithumb) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Price, error) {
var tickerPrice ticker.Price
tickers, err := b.GetAllTickers()
if err != nil {
return tickerPrice, err
}
for _, x := range b.GetEnabledPairs(assetType) {
currency := x.Base.String()
var tp ticker.Price
tp.Pair = x
tp.Low = tickers[currency].MinPrice
tp.Last = tickers[currency].ClosingPrice
tp.Volume = tickers[currency].UnitsTraded24Hr
tp.High = tickers[currency].MaxPrice
pairs := b.GetEnabledPairs(assetType)
for i := range pairs {
curr := pairs[i].Base.String()
if _, ok := tickers[curr]; !ok {
continue
}
tp := ticker.Price{
High: tickers[curr].MaxPrice,
Low: tickers[curr].MinPrice,
Volume: tickers[curr].UnitsTraded24Hr,
Open: tickers[curr].OpeningPrice,
Close: tickers[curr].ClosingPrice,
Pair: pairs[i],
}
err = ticker.ProcessTicker(b.Name, &tp, assetType)
if err != nil {
return tickerPrice, err
log.Error(log.Ticker, err)
}
}
return ticker.GetTicker(b.Name, p, assetType)

View File

@@ -1,6 +1,11 @@
package bitmex
import exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
import (
"time"
"github.com/thrasher-corp/gocryptotrader/currency"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
)
// RequestError allows for a general error capture from requests
type RequestError struct {
@@ -117,107 +122,107 @@ type Funding struct {
// Instrument Tradeable Contracts, Indices, and History
type Instrument struct {
AskPrice float64 `json:"askPrice"`
BankruptLimitDownPrice float64 `json:"bankruptLimitDownPrice"`
BankruptLimitUpPrice float64 `json:"bankruptLimitUpPrice"`
BidPrice float64 `json:"bidPrice"`
BuyLeg string `json:"buyLeg"`
CalcInterval string `json:"calcInterval"`
Capped bool `json:"capped"`
ClosingTimestamp string `json:"closingTimestamp"`
Deleverage bool `json:"deleverage"`
Expiry string `json:"expiry"`
FairBasis float64 `json:"fairBasis"`
FairBasisRate float64 `json:"fairBasisRate"`
FairMethod string `json:"fairMethod"`
FairPrice float64 `json:"fairPrice"`
Front string `json:"front"`
FundingBaseSymbol string `json:"fundingBaseSymbol"`
FundingInterval string `json:"fundingInterval"`
FundingPremiumSymbol string `json:"fundingPremiumSymbol"`
FundingQuoteSymbol string `json:"fundingQuoteSymbol"`
FundingRate float64 `json:"fundingRate"`
FundingTimestamp string `json:"fundingTimestamp"`
HasLiquidity bool `json:"hasLiquidity"`
HighPrice float64 `json:"highPrice"`
ImpactAskPrice float64 `json:"impactAskPrice"`
ImpactBidPrice float64 `json:"impactBidPrice"`
ImpactMidPrice float64 `json:"impactMidPrice"`
IndicativeFundingRate float64 `json:"indicativeFundingRate"`
IndicativeSettlePrice float64 `json:"indicativeSettlePrice"`
IndicativeTaxRate float64 `json:"indicativeTaxRate"`
InitMargin float64 `json:"initMargin"`
InsuranceFee float64 `json:"insuranceFee"`
InverseLeg string `json:"inverseLeg"`
IsInverse bool `json:"isInverse"`
IsQuanto bool `json:"isQuanto"`
LastChangePcnt float64 `json:"lastChangePcnt"`
LastPrice float64 `json:"lastPrice"`
LastPriceProtected float64 `json:"lastPriceProtected"`
LastTickDirection string `json:"lastTickDirection"`
Limit float64 `json:"limit"`
LimitDownPrice float64 `json:"limitDownPrice"`
LimitUpPrice float64 `json:"limitUpPrice"`
Listing string `json:"listing"`
LotSize int64 `json:"lotSize"`
LowPrice float64 `json:"lowPrice"`
MaintMargin float64 `json:"maintMargin"`
MakerFee float64 `json:"makerFee"`
MarkMethod string `json:"markMethod"`
MarkPrice float64 `json:"markPrice"`
MaxOrderQty int64 `json:"maxOrderQty"`
MaxPrice float64 `json:"maxPrice"`
MidPrice float64 `json:"midPrice"`
Multiplier int64 `json:"multiplier"`
OpenInterest int64 `json:"openInterest"`
OpenValue int64 `json:"openValue"`
OpeningTimestamp string `json:"openingTimestamp"`
OptionMultiplier float64 `json:"optionMultiplier"`
OptionStrikePcnt float64 `json:"optionStrikePcnt"`
OptionStrikePrice float64 `json:"optionStrikePrice"`
OptionStrikeRound float64 `json:"optionStrikeRound"`
OptionUnderlyingPrice float64 `json:"optionUnderlyingPrice"`
PositionCurrency string `json:"positionCurrency"`
PrevClosePrice float64 `json:"prevClosePrice"`
PrevPrice24h float64 `json:"prevPrice24h"`
PrevTotalTurnover int64 `json:"prevTotalTurnover"`
PrevTotalVolume int64 `json:"prevTotalVolume"`
PublishInterval string `json:"publishInterval"`
PublishTime string `json:"publishTime"`
QuoteCurrency string `json:"quoteCurrency"`
QuoteToSettleMultiplier int64 `json:"quoteToSettleMultiplier"`
RebalanceInterval string `json:"rebalanceInterval"`
RebalanceTimestamp string `json:"rebalanceTimestamp"`
Reference string `json:"reference"`
ReferenceSymbol string `json:"referenceSymbol"`
RelistInterval string `json:"relistInterval"`
RiskLimit int64 `json:"riskLimit"`
RiskStep int64 `json:"riskStep"`
RootSymbol string `json:"rootSymbol"`
SellLeg string `json:"sellLeg"`
SessionInterval string `json:"sessionInterval"`
SettlCurrency string `json:"settlCurrency"`
Settle string `json:"settle"`
SettledPrice float64 `json:"settledPrice"`
SettlementFee float64 `json:"settlementFee"`
State string `json:"state"`
Symbol string `json:"symbol"`
TakerFee float64 `json:"takerFee"`
Taxed bool `json:"taxed"`
TickSize float64 `json:"tickSize"`
Timestamp string `json:"timestamp"`
TotalTurnover int64 `json:"totalTurnover"`
TotalVolume int64 `json:"totalVolume"`
Turnover int64 `json:"turnover"`
Turnover24h int64 `json:"turnover24h"`
Typ string `json:"typ"`
Underlying string `json:"underlying"`
UnderlyingSymbol string `json:"underlyingSymbol"`
UnderlyingToPositionMultiplier int64 `json:"underlyingToPositionMultiplier"`
UnderlyingToSettleMultiplier int64 `json:"underlyingToSettleMultiplier"`
Volume int64 `json:"volume"`
Volume24h int64 `json:"volume24h"`
Vwap float64 `json:"vwap"`
AskPrice float64 `json:"askPrice"`
BankruptLimitDownPrice float64 `json:"bankruptLimitDownPrice"`
BankruptLimitUpPrice float64 `json:"bankruptLimitUpPrice"`
BidPrice float64 `json:"bidPrice"`
BuyLeg string `json:"buyLeg"`
CalcInterval string `json:"calcInterval"`
Capped bool `json:"capped"`
ClosingTimestamp string `json:"closingTimestamp"`
Deleverage bool `json:"deleverage"`
Expiry string `json:"expiry"`
FairBasis float64 `json:"fairBasis"`
FairBasisRate float64 `json:"fairBasisRate"`
FairMethod string `json:"fairMethod"`
FairPrice float64 `json:"fairPrice"`
Front string `json:"front"`
FundingBaseSymbol string `json:"fundingBaseSymbol"`
FundingInterval string `json:"fundingInterval"`
FundingPremiumSymbol string `json:"fundingPremiumSymbol"`
FundingQuoteSymbol string `json:"fundingQuoteSymbol"`
FundingRate float64 `json:"fundingRate"`
FundingTimestamp string `json:"fundingTimestamp"`
HasLiquidity bool `json:"hasLiquidity"`
HighPrice float64 `json:"highPrice"`
ImpactAskPrice float64 `json:"impactAskPrice"`
ImpactBidPrice float64 `json:"impactBidPrice"`
ImpactMidPrice float64 `json:"impactMidPrice"`
IndicativeFundingRate float64 `json:"indicativeFundingRate"`
IndicativeSettlePrice float64 `json:"indicativeSettlePrice"`
IndicativeTaxRate float64 `json:"indicativeTaxRate"`
InitMargin float64 `json:"initMargin"`
InsuranceFee float64 `json:"insuranceFee"`
InverseLeg string `json:"inverseLeg"`
IsInverse bool `json:"isInverse"`
IsQuanto bool `json:"isQuanto"`
LastChangePcnt float64 `json:"lastChangePcnt"`
LastPrice float64 `json:"lastPrice"`
LastPriceProtected float64 `json:"lastPriceProtected"`
LastTickDirection string `json:"lastTickDirection"`
Limit float64 `json:"limit"`
LimitDownPrice float64 `json:"limitDownPrice"`
LimitUpPrice float64 `json:"limitUpPrice"`
Listing string `json:"listing"`
LotSize int64 `json:"lotSize"`
LowPrice float64 `json:"lowPrice"`
MaintMargin float64 `json:"maintMargin"`
MakerFee float64 `json:"makerFee"`
MarkMethod string `json:"markMethod"`
MarkPrice float64 `json:"markPrice"`
MaxOrderQty int64 `json:"maxOrderQty"`
MaxPrice float64 `json:"maxPrice"`
MidPrice float64 `json:"midPrice"`
Multiplier int64 `json:"multiplier"`
OpenInterest int64 `json:"openInterest"`
OpenValue int64 `json:"openValue"`
OpeningTimestamp string `json:"openingTimestamp"`
OptionMultiplier float64 `json:"optionMultiplier"`
OptionStrikePcnt float64 `json:"optionStrikePcnt"`
OptionStrikePrice float64 `json:"optionStrikePrice"`
OptionStrikeRound float64 `json:"optionStrikeRound"`
OptionUnderlyingPrice float64 `json:"optionUnderlyingPrice"`
PositionCurrency string `json:"positionCurrency"`
PrevClosePrice float64 `json:"prevClosePrice"`
PrevPrice24h float64 `json:"prevPrice24h"`
PrevTotalTurnover int64 `json:"prevTotalTurnover"`
PrevTotalVolume int64 `json:"prevTotalVolume"`
PublishInterval string `json:"publishInterval"`
PublishTime string `json:"publishTime"`
QuoteCurrency string `json:"quoteCurrency"`
QuoteToSettleMultiplier int64 `json:"quoteToSettleMultiplier"`
RebalanceInterval string `json:"rebalanceInterval"`
RebalanceTimestamp string `json:"rebalanceTimestamp"`
Reference string `json:"reference"`
ReferenceSymbol string `json:"referenceSymbol"`
RelistInterval string `json:"relistInterval"`
RiskLimit int64 `json:"riskLimit"`
RiskStep int64 `json:"riskStep"`
RootSymbol string `json:"rootSymbol"`
SellLeg string `json:"sellLeg"`
SessionInterval string `json:"sessionInterval"`
SettlCurrency string `json:"settlCurrency"`
Settle string `json:"settle"`
SettledPrice float64 `json:"settledPrice"`
SettlementFee float64 `json:"settlementFee"`
State string `json:"state"`
Symbol currency.Pair `json:"symbol"`
TakerFee float64 `json:"takerFee"`
Taxed bool `json:"taxed"`
TickSize float64 `json:"tickSize"`
Timestamp time.Time `json:"timestamp"`
TotalTurnover int64 `json:"totalTurnover"`
TotalVolume int64 `json:"totalVolume"`
Turnover int64 `json:"turnover"`
Turnover24h int64 `json:"turnover24h"`
Typ string `json:"typ"`
Underlying string `json:"underlying"`
UnderlyingSymbol string `json:"underlyingSymbol"`
UnderlyingToPositionMultiplier int64 `json:"underlyingToPositionMultiplier"`
UnderlyingToSettleMultiplier int64 `json:"underlyingToSettleMultiplier"`
Volume float64 `json:"volume"`
Volume24h float64 `json:"volume24h"`
Vwap float64 `json:"vwap"`
}
// InstrumentInterval instrument interval

View File

@@ -2,7 +2,6 @@ package bitmex
import (
"errors"
"fmt"
"math"
"strings"
"sync"
@@ -93,7 +92,7 @@ func (b *Bitmex) SetDefaults() {
Websocket: true,
RESTCapabilities: exchange.ProtocolFeatures{
AutoPairUpdates: true,
TickerBatching: false,
TickerBatching: true,
},
WithdrawPermissions: exchange.AutoWithdrawCryptoWithAPIPermission |
exchange.WithdrawCryptoWithEmail |
@@ -205,7 +204,7 @@ func (b *Bitmex) FetchTradablePairs(asset asset.Item) ([]string, error) {
var products []string
for x := range marketInfo {
products = append(products, marketInfo[x].Symbol)
products = append(products, marketInfo[x].Symbol.String())
}
return products, nil
@@ -260,24 +259,34 @@ func (b *Bitmex) UpdateTradablePairs(forceUpdate bool) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (b *Bitmex) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Price, error) {
var tickerPrice ticker.Price
currency := b.FormatExchangeCurrency(p, assetType)
tick, err := b.GetTrade(&GenericRequestParams{
Symbol: currency.String(),
Reverse: true,
Count: 1})
tick, err := b.GetActiveInstruments(&GenericRequestParams{})
if err != nil {
return tickerPrice, err
}
if len(tick) == 0 {
return tickerPrice, fmt.Errorf("%s REST error: no ticker return", b.Name)
pairs := b.GetEnabledPairs(assetType)
for i := range pairs {
for j := range tick {
if !pairs[i].Equal(tick[j].Symbol) {
continue
}
tickerPrice = ticker.Price{
Last: tick[j].LastPrice,
High: tick[j].HighPrice,
Low: tick[j].LowPrice,
Bid: tick[j].BidPrice,
Ask: tick[j].AskPrice,
Volume: tick[j].Volume24h,
Close: tick[j].PrevClosePrice,
Pair: tick[j].Symbol,
LastUpdated: tick[j].Timestamp,
}
err = ticker.ProcessTicker(b.Name, &tickerPrice, assetType)
if err != nil {
log.Error(log.Ticker, err)
}
}
}
tickerPrice.Pair = p
tickerPrice.Last = tick[0].Price
tickerPrice.Volume = float64(tick[0].Size)
return tickerPrice, ticker.ProcessTicker(b.Name, &tickerPrice, assetType)
return ticker.GetTicker(b.Name, p, assetType)
}
// FetchTicker returns the ticker for a currency pair

View File

@@ -51,8 +51,8 @@ const (
bitstampAPIReturnType = "string"
bitstampAPITradingPairsInfo = "trading-pairs-info"
bitstampAuthRate = 600
bitstampUnauthRate = 600
bitstampAuthRate = 8000
bitstampUnauthRate = 8000
)
// Bitstamp is the overarching type across the bitstamp package

View File

@@ -71,7 +71,6 @@ func (b *Bitstamp) SetDefaults() {
Websocket: true,
RESTCapabilities: exchange.ProtocolFeatures{
AutoPairUpdates: true,
TickerBatching: false,
},
WithdrawPermissions: exchange.AutoWithdrawCrypto |
exchange.AutoWithdrawFiat,
@@ -206,15 +205,19 @@ func (b *Bitstamp) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.P
tick, err := b.GetTicker(p.String(), false)
if err != nil {
return tickerPrice, err
}
tickerPrice.Pair = p
tickerPrice.Ask = tick.Ask
tickerPrice.Bid = tick.Bid
tickerPrice.Low = tick.Low
tickerPrice.Last = tick.Last
tickerPrice.Volume = tick.Volume
tickerPrice.High = tick.High
tickerPrice = ticker.Price{
Last: tick.Last,
High: tick.High,
Low: tick.Low,
Bid: tick.Bid,
Ask: tick.Ask,
Volume: tick.Volume,
Open: tick.Open,
Pair: p,
LastUpdated: time.Unix(tick.Timestamp, 0),
}
err = ticker.ProcessTicker(b.GetName(), &tickerPrice, assetType)
if err != nil {

View File

@@ -1,6 +1,8 @@
package bittrex
import "encoding/json"
import (
"encoding/json"
)
// Response is the generalised response type for Bittrex
type Response struct {

View File

@@ -196,27 +196,36 @@ func (b *Bittrex) GetAccountInfo() (exchange.AccountInfo, error) {
// UpdateTicker updates and returns the ticker for a currency pair
func (b *Bittrex) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Price, error) {
var tickerPrice ticker.Price
tick, err := b.GetMarketSummaries()
ticks, err := b.GetMarketSummaries()
if err != nil {
return tickerPrice, err
}
for _, x := range b.GetEnabledPairs(assetType) {
curr := b.FormatExchangeCurrency(x, assetType)
for y := range tick.Result {
if tick.Result[y].MarketName != curr.String() {
pairs := b.GetEnabledPairs(assetType)
for i := range pairs {
for j := range ticks.Result {
if !strings.EqualFold(ticks.Result[j].MarketName, pairs[i].String()) {
continue
}
tickerPrice.Pair = x
tickerPrice.High = tick.Result[y].High
tickerPrice.Low = tick.Result[y].Low
tickerPrice.Ask = tick.Result[y].Ask
tickerPrice.Bid = tick.Result[y].Bid
tickerPrice.Last = tick.Result[y].Last
tickerPrice.Volume = tick.Result[y].Volume
ticker.ProcessTicker(b.GetName(), &tickerPrice, assetType)
tickerTime, _ := time.Parse(time.RFC3339, ticks.Result[j].TimeStamp)
tickerPrice = ticker.Price{
Last: ticks.Result[j].Last,
High: ticks.Result[j].High,
Low: ticks.Result[j].Low,
Bid: ticks.Result[j].Bid,
Ask: ticks.Result[j].Ask,
Volume: ticks.Result[j].BaseVolume,
QuoteVolume: ticks.Result[j].Volume,
Close: ticks.Result[j].PrevDay,
Pair: pairs[i],
LastUpdated: tickerTime,
}
err = ticker.ProcessTicker(b.GetName(), &tickerPrice, assetType)
if err != nil {
log.Error(log.Ticker, err)
}
}
}
return ticker.GetTicker(b.Name, p, assetType)
}

View File

@@ -30,13 +30,16 @@ type Market struct {
// Ticker holds ticker information
type Ticker struct {
BestBID float64 `json:"bestBid"`
BestAsk float64 `json:"bestAsk"`
LastPrice float64 `json:"lastPrice"`
Currency string `json:"currency"`
Instrument string `json:"instrument"`
Timestamp int64 `json:"timestamp"`
Volume float64 `json:"volume24h"`
BestAsk float64 `json:"bestAsk"`
BestBid float64 `json:"bestBid"`
Currency currency.Code `json:"currency"`
High24h float64 `json:"high24h"`
Instrument currency.Pair `json:"instrument"`
LastPrice float64 `json:"lastPrice"`
Low24h float64 `json:"low24h"`
Price24h float64 `json:"price24h"`
Timestamp int64 `json:"timestamp"`
Volume24h float64 `json:"volume24h"`
}
// Orderbook holds current orderbook information returned from the exchange

View File

@@ -147,7 +147,7 @@ func (b *BTCMarkets) FetchTradablePairs(asset asset.Item) ([]string, error) {
var pairs []string
for x := range markets {
pairs = append(pairs, markets[x].Instrument+"-"+markets[x].Currency)
pairs = append(pairs, fmt.Sprintf("%v%v%v", markets[x].Instrument, b.GetPairFormat(asset, false).Delimiter, markets[x].Currency))
}
return pairs, nil
@@ -171,10 +171,17 @@ func (b *BTCMarkets) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker
if err != nil {
return tickerPrice, err
}
tickerPrice.Pair = p
tickerPrice.Ask = tick.BestAsk
tickerPrice.Bid = tick.BestBID
tickerPrice.Last = tick.LastPrice
tickerPrice = ticker.Price{
Last: tick.LastPrice,
High: tick.High24h,
Low: tick.Low24h,
Bid: tick.BestBid,
Ask: tick.BestAsk,
Volume: tick.Volume24h,
Pair: p,
LastUpdated: time.Unix(tick.Timestamp, 0),
}
err = ticker.ProcessTicker(b.GetName(), &tickerPrice, assetType)
if err != nil {

View File

@@ -55,12 +55,12 @@ type Orderbook struct {
// MarketStatistics stores market statistics for a particular product
type MarketStatistics struct {
Open float64 `json:"open,string"`
Low float64 `json:"low,string"`
High float64 `json:"high,string"`
Close float64 `json:"close,string"`
Volume float64 `json:"volume,string"`
Time string `json:"time"`
Open float64 `json:"open,string"`
Low float64 `json:"low,string"`
High float64 `json:"high,string"`
Close float64 `json:"close,string"`
Volume float64 `json:"volume,string"`
Time time.Time `json:"time"`
}
// ServerTime stores the server time data

View File

@@ -94,12 +94,12 @@ func (b *BTSE) WsHandleData() {
}
b.Websocket.DataHandler <- wshandler.TickerData{
Timestamp: time.Now(),
Pair: currency.NewPairDelimiter(t.ProductID, "-"),
AssetType: asset.Spot,
Exchange: b.GetName(),
ClosePrice: price,
Quantity: t.LastSize,
Exchange: b.Name,
Close: price,
Bid: t.BestBids,
Ask: t.BestAsk,
AssetType: asset.Spot,
Pair: currency.NewPairDelimiter(t.ProductID, b.GetPairFormat(asset.Spot, false).Delimiter),
}
case "snapshot":
snapshot := websocketOrderbookSnapshot{}

View File

@@ -219,6 +219,7 @@ func (b *BTSE) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Price
tickerPrice.Last = t.Price
tickerPrice.Volume = s.Volume
tickerPrice.High = s.High
tickerPrice.LastUpdated = s.Time
err = ticker.ProcessTicker(b.GetName(), &tickerPrice, assetType)
if err != nil {

View File

@@ -1,6 +1,10 @@
package coinbasepro
import "time"
import (
"time"
"github.com/thrasher-corp/gocryptotrader/currency"
)
// Product holds product information
type Product struct {
@@ -15,10 +19,13 @@ type Product struct {
// Ticker holds basic ticker information
type Ticker struct {
TradeID int64 `json:"trade_id"`
Price float64 `json:"price,string"`
Size float64 `json:"size,string"`
Time string `json:"time"`
TradeID int64 `json:"trade_id"`
Ask float64 `json:"ask,string"`
Bid float64 `json:"bid,string"`
Price float64 `json:"price,string"`
Size float64 `json:"size,string"`
Volume float64 `json:"volume,string"`
Time time.Time `json:"time"`
}
// Trade holds executed trade information
@@ -435,21 +442,21 @@ type WebsocketHeartBeat struct {
// WebsocketTicker defines ticker websocket response
type WebsocketTicker struct {
Type string `json:"type"`
Sequence int64 `json:"sequence"`
ProductID string `json:"product_id"`
Price float64 `json:"price,string"`
Open24H float64 `json:"open_24h,string"`
Volume24H float64 `json:"volumen_24h,string"`
Low24H float64 `json:"low_24h,string"`
High24H float64 `json:"high_24h,string"`
Volume30D float64 `json:"volume_30d,string"`
BestBid float64 `json:"best_bid,string"`
BestAsk float64 `json:"best_ask,string"`
Side string `json:"side"`
Time time.Time `json:"time,string"`
TradeID int64 `json:"trade_id"`
LastSize float64 `json:"last_size,string"`
Type string `json:"type"`
Sequence int64 `json:"sequence"`
ProductID currency.Pair `json:"product_id"`
Price float64 `json:"price,string"`
Open24H float64 `json:"open_24h,string"`
Volume24H float64 `json:"volume_24h,string"`
Low24H float64 `json:"low_24h,string"`
High24H float64 `json:"high_24h,string"`
Volume30D float64 `json:"volume_30d,string"`
BestBid float64 `json:"best_bid,string"`
BestAsk float64 `json:"best_ask,string"`
Side string `json:"side"`
Time time.Time `json:"time,string"`
TradeID int64 `json:"trade_id"`
LastSize float64 `json:"last_size,string"`
}
// WebsocketOrderbookSnapshot defines a snapshot response

View File

@@ -89,15 +89,18 @@ func (c *CoinbasePro) WsHandleData() {
}
c.Websocket.DataHandler <- wshandler.TickerData{
Timestamp: ticker.Time,
Pair: currency.NewPairFromString(ticker.ProductID),
AssetType: asset.Spot,
Exchange: c.GetName(),
OpenPrice: ticker.Open24H,
HighPrice: ticker.High24H,
LowPrice: ticker.Low24H,
ClosePrice: ticker.Price,
Quantity: ticker.Volume24H,
Timestamp: ticker.Time,
Pair: ticker.ProductID,
AssetType: asset.Spot,
Exchange: c.Name,
Open: ticker.Open24H,
High: ticker.High24H,
Low: ticker.Low24H,
Close: ticker.Price,
Volume: ticker.Volume24H,
Bid: ticker.BestBid,
Ask: ticker.BestAsk,
Last: ticker.LastSize,
}
case "snapshot":

View File

@@ -232,18 +232,22 @@ func (c *CoinbasePro) UpdateTicker(p currency.Pair, assetType asset.Item) (ticke
if err != nil {
return ticker.Price{}, err
}
stats, err := c.GetStats(c.FormatExchangeCurrency(p, assetType).String())
if err != nil {
return ticker.Price{}, err
}
tickerPrice.Pair = p
tickerPrice.Volume = stats.Volume
tickerPrice.Last = tick.Price
tickerPrice.High = stats.High
tickerPrice.Low = stats.Low
tickerPrice = ticker.Price{
Last: tick.Size,
High: stats.High,
Low: stats.Low,
Bid: tick.Bid,
Ask: tick.Ask,
Volume: tick.Volume,
Open: stats.Open,
Pair: p,
LastUpdated: tick.Time,
}
err = ticker.ProcessTicker(c.GetName(), &tickerPrice, assetType)
if err != nil {

View File

@@ -33,7 +33,7 @@ type Ticker struct {
Last float64 `json:"last,string"`
LowestSell float64 `json:"lowest_sell,string"`
OpenInterest float64 `json:"open_interest,string"`
Timestamp float64 `json:"timestamp"`
Timestamp int64 `json:"timestamp"`
TransID int64 `json:"trans_id"`
Volume float64 `json:"volume,string"`
Volume24 float64 `json:"volume24,string"`
@@ -280,16 +280,23 @@ type wsHeartbeatResp struct {
// WsTicker defines the resp for ticker updates from the websocket connection
type WsTicker struct {
HighestBuy float64 `json:"highest_buy,string"`
InstID int64 `json:"inst_id"`
Last float64 `json:"last,string"`
LowestSell float64 `json:"lowest_sell,string"`
OpenInterest float64 `json:"open_interest,string"`
Reply string `json:"reply"`
Timestamp int64 `json:"timestamp"`
TransID int64 `json:"trans_id"`
Volume float64 `json:"volume,string"`
Volume24H float64 `json:"volume24,string"`
High24 float64 `json:"high24,string"`
HighestBuy float64 `json:"highest_buy,string"`
InstID int64 `json:"inst_id"`
Last float64 `json:"last,string"`
Low24 float64 `json:"low24,string"`
LowestSell float64 `json:"lowest_sell,string"`
Nonce int64 `json:"nonce"`
PrevTransID int64 `json:"prev_trans_id"`
PriceChange24 float64 `json:"price_change_24,string"`
Reply string `json:"reply"`
Status []string `json:"status"`
Timestamp int64 `json:"timestamp"`
TransID int64 `json:"trans_id"`
Volume float64 `json:"volume,string"`
Volume24 float64 `json:"volume24,string"`
Volume24Quote float64 `json:"volume24_quote,string"`
VolumeQuote float64 `json:"volume_quote,string"`
}
// WsOrderbookSnapshot defines the resp for orderbook snapshot updates from

View File

@@ -139,14 +139,15 @@ func (c *COINUT) wsProcessResponse(resp []byte) {
}
currencyPair := instrumentListByCode[ticker.InstID]
c.Websocket.DataHandler <- wshandler.TickerData{
Timestamp: time.Unix(0, ticker.Timestamp),
Pair: currency.NewPairFromString(currencyPair),
Exchange: c.GetName(),
AssetType: asset.Spot,
HighPrice: ticker.HighestBuy,
LowPrice: ticker.LowestSell,
ClosePrice: ticker.Last,
Quantity: ticker.Volume,
Exchange: c.Name,
Volume: ticker.Volume,
QuoteVolume: ticker.VolumeQuote,
High: ticker.HighestBuy,
Low: ticker.LowestSell,
Last: ticker.Last,
Timestamp: time.Unix(0, ticker.Timestamp),
AssetType: asset.Spot,
Pair: currency.NewPairFromString(currencyPair),
}
case "inst_order_book":
@@ -245,9 +246,9 @@ func (c *COINUT) WsSetInstrumentList() error {
if err != nil {
return err
}
for currency, data := range list.Spot {
instrumentListByString[currency] = data[0].InstID
instrumentListByCode[data[0].InstID] = currency
for curr, data := range list.Spot {
instrumentListByString[curr] = data[0].InstID
instrumentListByCode[data[0].InstID] = curr
}
if len(instrumentListByString) == 0 || len(instrumentListByCode) == 0 {
return errors.New("instrument lists failed to populate")
@@ -414,11 +415,11 @@ func (c *COINUT) wsSubmitOrder(order *WsSubmitOrderParameters) (*WsStandardOrder
if !c.Websocket.CanUseAuthenticatedEndpoints() {
return nil, fmt.Errorf("%v not authorised to submit order", c.Name)
}
currency := c.FormatExchangeCurrency(order.Currency, asset.Spot).String()
curr := c.FormatExchangeCurrency(order.Currency, asset.Spot).String()
var orderSubmissionRequest WsSubmitOrderRequest
orderSubmissionRequest.Request = "new_order"
orderSubmissionRequest.Nonce = c.WebsocketConn.GenerateMessageID(false)
orderSubmissionRequest.InstID = instrumentListByString[currency]
orderSubmissionRequest.InstID = instrumentListByString[curr]
orderSubmissionRequest.Qty = order.Amount
orderSubmissionRequest.Price = order.Price
orderSubmissionRequest.Side = string(order.Side)
@@ -523,13 +524,13 @@ func (c *COINUT) wsSubmitOrders(orders []WsSubmitOrderParameters) ([]WsStandardO
}
orderRequest := WsSubmitOrdersRequest{}
for i := range orders {
currency := c.FormatExchangeCurrency(orders[i].Currency, asset.Spot).String()
curr := c.FormatExchangeCurrency(orders[i].Currency, asset.Spot).String()
orderRequest.Orders = append(orderRequest.Orders,
WsSubmitOrdersRequestData{
Qty: orders[i].Amount,
Price: orders[i].Price,
Side: string(orders[i].Side),
InstID: instrumentListByString[currency],
InstID: instrumentListByString[curr],
ClientOrdID: i + 1,
})
}
@@ -582,11 +583,11 @@ func (c *COINUT) wsGetOpenOrders(p currency.Pair) error {
if !c.Websocket.CanUseAuthenticatedEndpoints() {
return fmt.Errorf("%v not authorised to get open orders", c.Name)
}
currency := c.FormatExchangeCurrency(p, asset.Spot).String()
curr := c.FormatExchangeCurrency(p, asset.Spot).String()
var openOrdersRequest WsGetOpenOrdersRequest
openOrdersRequest.Request = "user_open_orders"
openOrdersRequest.Nonce = c.WebsocketConn.GenerateMessageID(false)
openOrdersRequest.InstID = instrumentListByString[currency]
openOrdersRequest.InstID = instrumentListByString[curr]
resp, err := c.WebsocketConn.SendMessageReturnResponse(openOrdersRequest.Nonce, openOrdersRequest)
if err != nil {
@@ -679,10 +680,10 @@ func (c *COINUT) wsGetTradeHistory(p currency.Pair, start, limit int64) error {
if !c.Websocket.CanUseAuthenticatedEndpoints() {
return fmt.Errorf("%v not authorised to get trade history", c.Name)
}
currency := c.FormatExchangeCurrency(p, asset.Spot).String()
curr := c.FormatExchangeCurrency(p, asset.Spot).String()
var request WsTradeHistoryRequest
request.Request = "trade_history"
request.InstID = instrumentListByString[currency]
request.InstID = instrumentListByString[curr]
request.Nonce = c.WebsocketConn.GenerateMessageID(false)
request.Start = start
request.Limit = limit

View File

@@ -278,17 +278,18 @@ func (c *COINUT) GetAccountInfo() (exchange.AccountInfo, error) {
// UpdateTicker updates and returns the ticker for a currency pair
func (c *COINUT) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Price, error) {
var tickerPrice ticker.Price
tick, err := c.GetInstrumentTicker(c.InstrumentMap[p.String()])
tick, err := c.GetInstrumentTicker(c.InstrumentMap[c.FormatExchangeCurrency(p, assetType).String()])
if err != nil {
return ticker.Price{}, err
return tickerPrice, err
}
tickerPrice = ticker.Price{
Last: tick.Last,
High: tick.HighestBuy,
Low: tick.LowestSell,
Volume: tick.Volume24,
Pair: p,
LastUpdated: time.Unix(0, tick.Timestamp),
}
tickerPrice.Pair = p
tickerPrice.Volume = tick.Volume
tickerPrice.Last = tick.Last
tickerPrice.High = tick.HighestBuy
tickerPrice.Low = tick.LowestSell
err = ticker.ProcessTicker(c.GetName(), &tickerPrice, assetType)
if err != nil {
return tickerPrice, err

View File

@@ -68,9 +68,8 @@ func (e *EXMO) GetOrderbook(symbol string) (map[string]Orderbook, error) {
}
// GetTicker returns the ticker for a symbol or symbols
func (e *EXMO) GetTicker(symbol string) (map[string]Ticker, error) {
func (e *EXMO) GetTicker() (map[string]Ticker, error) {
v := url.Values{}
v.Set("pair", symbol)
result := make(map[string]Ticker)
urlPath := fmt.Sprintf("%s/v%s/%s", e.API.Endpoints.URL, exmoAPIVersion, exmoTicker)
return result, e.SendHTTPRequest(common.EncodeURLValues(urlPath, v), &result)

View File

@@ -56,7 +56,7 @@ func TestGetOrderbook(t *testing.T) {
func TestGetTicker(t *testing.T) {
t.Parallel()
_, err := e.GetTicker("BTC_USD")
_, err := e.GetTicker()
if err != nil {
t.Errorf("Test failed. Err: %s", err)
}

View File

@@ -73,7 +73,7 @@ func (e *EXMO) SetDefaults() {
Websocket: false,
RESTCapabilities: exchange.ProtocolFeatures{
AutoPairUpdates: true,
TickerBatching: false,
TickerBatching: true,
},
WithdrawPermissions: exchange.AutoWithdrawCryptoWithSetup |
exchange.NoFiatWithdrawals,
@@ -156,31 +156,32 @@ func (e *EXMO) UpdateTradablePairs(forceUpdate bool) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (e *EXMO) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Price, error) {
var tickerPrice ticker.Price
pairsCollated, err := e.FormatExchangeCurrencies(e.GetEnabledPairs(assetType), assetType)
result, err := e.GetTicker()
if err != nil {
return tickerPrice, err
}
result, err := e.GetTicker(pairsCollated)
if err != nil {
if _, ok := result[p.String()]; !ok {
return tickerPrice, err
}
for _, x := range e.GetEnabledPairs(assetType) {
currency := e.FormatExchangeCurrency(x, assetType).String()
var tickerPrice ticker.Price
tickerPrice.Pair = x
tickerPrice.Last = result[currency].Last
tickerPrice.Ask = result[currency].Sell
tickerPrice.High = result[currency].High
tickerPrice.Bid = result[currency].Buy
tickerPrice.Last = result[currency].Last
tickerPrice.Low = result[currency].Low
tickerPrice.Volume = result[currency].Volume
err = ticker.ProcessTicker(e.Name, &tickerPrice, assetType)
if err != nil {
return tickerPrice, err
pairs := e.GetEnabledPairs(assetType)
for i := range pairs {
for j := range result {
if !strings.EqualFold(pairs[i].String(), j) {
continue
}
tickerPrice = ticker.Price{
Pair: pairs[i],
Last: result[j].Last,
Ask: result[j].Sell,
High: result[j].High,
Bid: result[j].Buy,
Low: result[j].Low,
Volume: result[j].Volume,
}
err = ticker.ProcessTicker(e.Name, &tickerPrice, assetType)
if err != nil {
log.Error(log.Ticker, err)
}
}
}
return ticker.GetTicker(e.Name, p, assetType)

View File

@@ -70,15 +70,15 @@ type KLineResponse struct {
// TickerResponse holds the ticker response data
type TickerResponse struct {
Result string `json:"result"`
Volume float64 `json:"baseVolume,string"` // Trading volume
High float64 `json:"high24hr,string"` // 24 hour high price
Open float64 `json:"highestBid,string"` // Openening price
Last float64 `json:"last,string"` // Last price
Low float64 `json:"low24hr,string"` // 24 hour low price
Close float64 `json:"lowestAsk,string"` // Closing price
PercentChange float64 `json:"percentChange,string"` // Percentage change
QuoteVolume float64 `json:"quoteVolume,string"` // Quote currency volume
Period int64 `json:"period"`
BaseVolume float64 `json:"baseVolume,string"`
Change float64 `json:"change,string"`
Close float64 `json:"close,string"`
High float64 `json:"high,string"`
Last float64 `json:"last,string"`
Low float64 `json:"low,string"`
Open float64 `json:"open,string"`
QuoteVolume float64 `json:"quoteVolume,string"`
}
// OrderbookResponse stores the orderbook data

View File

@@ -136,15 +136,16 @@ func (g *Gateio) WsHandleData() {
}
g.Websocket.DataHandler <- wshandler.TickerData{
Timestamp: time.Now(),
Pair: currency.NewPairFromString(c),
AssetType: asset.Spot,
Exchange: g.GetName(),
ClosePrice: ticker.Close,
Quantity: ticker.BaseVolume,
OpenPrice: ticker.Open,
HighPrice: ticker.High,
LowPrice: ticker.Low,
Exchange: g.Name,
Open: ticker.Open,
Close: ticker.Close,
Volume: ticker.BaseVolume,
QuoteVolume: ticker.QuoteVolume,
High: ticker.High,
Low: ticker.Low,
Last: ticker.Last,
AssetType: asset.Spot,
Pair: currency.NewPairFromString(c),
}
case strings.Contains(result.Method, "trades"):
@@ -238,7 +239,7 @@ func (g *Gateio) WsHandleData() {
newOrderBook.Pair = currency.NewPairFromString(c)
err = g.Websocket.Orderbook.LoadSnapshot(&newOrderBook,
false)
true)
if err != nil {
g.Websocket.DataHandler <- err
}

View File

@@ -198,20 +198,26 @@ func (g *Gateio) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Pri
if err != nil {
return tickerPrice, err
}
for _, x := range g.GetEnabledPairs(assetType) {
currency := g.FormatExchangeCurrency(x, assetType).String()
var tp ticker.Price
tp.Pair = x
tp.High = result[currency].High
tp.Last = result[currency].Last
tp.Last = result[currency].Last
tp.Low = result[currency].Low
tp.Volume = result[currency].Volume
err = ticker.ProcessTicker(g.Name, &tp, assetType)
if err != nil {
return tickerPrice, err
pairs := g.GetEnabledPairs(assetType)
for i := range pairs {
for k := range result {
if !strings.EqualFold(k, pairs[i].String()) {
continue
}
tickerPrice = ticker.Price{
Last: result[k].Last,
High: result[k].High,
Low: result[k].Low,
Volume: result[k].BaseVolume,
QuoteVolume: result[k].QuoteVolume,
Open: result[k].Open,
Close: result[k].Close,
Pair: pairs[i],
}
err = ticker.ProcessTicker(g.Name, &tickerPrice, assetType)
if err != nil {
log.Error(log.Ticker, err)
}
}
}

View File

@@ -74,48 +74,20 @@ func (g *Gemini) GetSymbols() ([]string, error) {
}
// GetTicker returns information about recent trading activity for the symbol
func (g *Gemini) GetTicker(currencyPair string) (Ticker, error) {
type TickerResponse struct {
Ask float64 `json:"ask,string"`
Bid float64 `json:"bid,string"`
Last float64 `json:"last,string"`
Volume map[string]interface{}
Message string `json:"message"`
}
ticker := Ticker{}
resp := TickerResponse{}
path := fmt.Sprintf("%s/v%s/%s/%s", g.API.Endpoints.URL, geminiAPIVersion, geminiTicker, currencyPair)
err := g.SendHTTPRequest(path, &resp)
func (g *Gemini) GetTicker(currencyPair string) (TickerV2, error) {
ticker := TickerV2{}
path := fmt.Sprintf("%s/v2/ticker/%s", g.API.Endpoints.URL, currencyPair)
err := g.SendHTTPRequest(path, &ticker)
if err != nil {
return ticker, err
}
if resp.Message != "" {
return ticker, errors.New(resp.Message)
if ticker.Result == "error" {
return ticker, fmt.Errorf("%v %v %v",
g.Name,
ticker.Reason,
ticker.Message)
}
ticker.Ask = resp.Ask
ticker.Bid = resp.Bid
ticker.Last = resp.Last
ticker.Volume.Currency, _ = strconv.ParseFloat(resp.Volume[currencyPair[0:3]].(string), 64)
if strings.Contains(currencyPair, "USD") {
ticker.Volume.USD, _ = strconv.ParseFloat(resp.Volume["USD"].(string), 64)
} else {
if resp.Volume["ETH"] != nil {
ticker.Volume.ETH, _ = strconv.ParseFloat(resp.Volume["ETH"].(string), 64)
}
if resp.Volume["BTC"] != nil {
ticker.Volume.BTC, _ = strconv.ParseFloat(resp.Volume["BTC"].(string), 64)
}
}
time, _ := resp.Volume["timestamp"].(float64)
ticker.Volume.Timestamp = int64(time)
return ticker, nil
}

View File

@@ -16,6 +16,21 @@ type Ticker struct {
}
}
// TickerV2 holds returned ticker data from the exchange
type TickerV2 struct {
Ask float64 `json:"ask,string"`
Bid float64 `json:"bid,string"`
Changes []string `json:"changes"`
Close float64 `json:"close,string"`
High float64 `json:"high,string"`
Low float64 `json:"low,string"`
Open float64 `json:"open,string"`
Message string `json:"message,omitempty"`
Reason string `json:"reason,omitempty"`
Result string `json:"result,omitempty"`
Symbol currency.Pair `json:"symbol"`
}
// Orderbook contains orderbook information for both bid and ask side
type Orderbook struct {
Bids []OrderbookEntry `json:"bids"`

View File

@@ -222,12 +222,15 @@ func (g *Gemini) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Pri
if err != nil {
return tickerPrice, err
}
tickerPrice.Pair = p
tickerPrice.Ask = tick.Ask
tickerPrice.Bid = tick.Bid
tickerPrice.Last = tick.Last
tickerPrice.Volume = tick.Volume.USD
tickerPrice = ticker.Price{
High: tick.High,
Low: tick.Low,
Bid: tick.Bid,
Ask: tick.Ask,
Open: tick.Open,
Close: tick.Close,
Pair: p,
}
err = ticker.ProcessTicker(g.GetName(), &tickerPrice, assetType)
if err != nil {
return tickerPrice, err

View File

@@ -116,65 +116,17 @@ func (h *HitBTC) GetSymbolsDetailed() ([]Symbol, error) {
}
// GetTicker returns ticker information
func (h *HitBTC) GetTicker(symbol string) (map[string]Ticker, error) {
var resp1 []TickerResponse
resp2 := TickerResponse{}
ret := make(map[string]TickerResponse)
result := make(map[string]Ticker)
func (h *HitBTC) GetTicker(symbol string) (TickerResponse, error) {
var resp TickerResponse
path := fmt.Sprintf("%s/%s/%s", h.API.Endpoints.URL, apiV2Ticker, symbol)
var err error
return resp, h.SendHTTPRequest(path, &resp)
}
if symbol == "" {
err = h.SendHTTPRequest(path, &resp1)
if err != nil {
return nil, err
}
for i := range resp1 {
if resp1[i].Symbol != "" {
ret[resp1[i].Symbol] = resp1[i]
}
}
} else {
err = h.SendHTTPRequest(path, &resp2)
ret[resp2.Symbol] = resp2
}
if err == nil {
for i := range ret {
tick := Ticker{}
ask, _ := strconv.ParseFloat(ret[i].Ask, 64)
tick.Ask = ask
bid, _ := strconv.ParseFloat(ret[i].Bid, 64)
tick.Bid = bid
high, _ := strconv.ParseFloat(ret[i].High, 64)
tick.High = high
last, _ := strconv.ParseFloat(ret[i].Last, 64)
tick.Last = last
low, _ := strconv.ParseFloat(ret[i].Low, 64)
tick.Low = low
open, _ := strconv.ParseFloat(ret[i].Open, 64)
tick.Open = open
vol, _ := strconv.ParseFloat(ret[i].Volume, 64)
tick.Volume = vol
volQuote, _ := strconv.ParseFloat(ret[i].VolumeQuote, 64)
tick.VolumeQuote = volQuote
tick.Symbol = ret[i].Symbol
tick.Timestamp = ret[i].Timestamp
result[i] = tick
}
}
return result, err
// GetTickers returns ticker information
func (h *HitBTC) GetTickers() ([]TickerResponse, error) {
var resp []TickerResponse
path := fmt.Sprintf("%s/%s/", h.API.Endpoints.URL, apiV2Ticker)
return resp, h.SendHTTPRequest(path, &resp)
}
// GetTrades returns trades from hitbtc

View File

@@ -97,6 +97,20 @@ func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
}
}
func TestGetAllTickers(t *testing.T) {
_, err := h.GetTickers()
if err != nil {
t.Error(err)
}
}
func TestGetSingularTicker(t *testing.T) {
_, err := h.GetTicker("BTCUSD")
if err != nil {
t.Error(err)
}
}
func TestGetFee(t *testing.T) {
h.SetDefaults()
TestSetup(t)

View File

@@ -6,32 +6,18 @@ import (
"github.com/thrasher-corp/gocryptotrader/currency"
)
// Ticker holds ticker information
type Ticker struct {
Last float64
Ask float64
Bid float64
Timestamp time.Time
Volume float64
VolumeQuote float64
Symbol string
High float64
Low float64
Open float64
}
// TickerResponse is the response type
type TickerResponse struct {
Last string `json:"last"` // Last trade price
Ask string `json:"ask"` // Best ask price
Bid string `json:"bid"` // Best bid price
Timestamp time.Time `json:"timestamp,string"` // Last update or refresh ticker timestamp
Volume string `json:"volume"` // Total trading amount within 24 hours in base currency
VolumeQuote string `json:"volumeQuote"` // Total trading amount within 24 hours in quote currency
Symbol string `json:"symbol"`
High string `json:"high"` // Highest trade price within 24 hours
Low string `json:"low"` // Lowest trade price within 24 hours
Open string `json:"open"` // Last trade price 24 hours ago
Ask float64 `json:"ask,string"`
Bid float64 `json:"bid,string"`
High float64 `json:"high,string"`
Last float64 `json:"last,string"`
Low float64 `json:"low,string"`
Open float64 `json:"open,string"`
Volume float64 `json:"volume,string"`
VolumeQuote float64 `json:"volumeQuote,string"`
Symbol currency.Pair `json:"symbol"`
Timestamp time.Time `json:"timestamp"`
}
// Symbol holds symbol data
@@ -336,16 +322,16 @@ type params struct {
// WsTicker defines websocket ticker feed return params
type WsTicker struct {
Params struct {
Ask float64 `json:"ask,string"`
Bid float64 `json:"bid,string"`
Last float64 `json:"last,string"`
Open float64 `json:"open,string"`
Low float64 `json:"low,string"`
High float64 `json:"high,string"`
Volume float64 `json:"volume,string"`
VolumeQuote float64 `json:"volumeQuote,string"`
Timestamp string `json:"timestamp"`
Symbol string `json:"symbol"`
Ask float64 `json:"ask,string"`
Bid float64 `json:"bid,string"`
Last float64 `json:"last,string"`
Open float64 `json:"open,string"`
Low float64 `json:"low,string"`
High float64 `json:"high,string"`
Volume float64 `json:"volume,string"`
VolumeQuote float64 `json:"volumeQuote,string"`
Timestamp string `json:"timestamp"`
Symbol currency.Pair `json:"symbol"`
} `json:"params"`
}

View File

@@ -116,14 +116,18 @@ func (h *HitBTC) handleSubscriptionUpdates(resp wshandler.WebsocketResponse, ini
return
}
h.Websocket.DataHandler <- wshandler.TickerData{
Exchange: h.GetName(),
AssetType: asset.Spot,
Pair: currency.NewPairFromString(ticker.Params.Symbol),
Quantity: ticker.Params.Volume,
Timestamp: ts,
OpenPrice: ticker.Params.Open,
HighPrice: ticker.Params.High,
LowPrice: ticker.Params.Low,
Exchange: h.Name,
Open: ticker.Params.Open,
Volume: ticker.Params.Volume,
QuoteVolume: ticker.Params.VolumeQuote,
High: ticker.Params.High,
Low: ticker.Params.Low,
Bid: ticker.Params.Bid,
Ask: ticker.Params.Ask,
Last: ticker.Params.Last,
Timestamp: ts,
AssetType: asset.Spot,
Pair: ticker.Params.Symbol,
}
case "snapshotOrderbook":
var obSnapshot WsOrderbook

View File

@@ -196,7 +196,7 @@ func (h *HitBTC) FetchTradablePairs(asset asset.Item) ([]string, error) {
var pairs []string
for x := range symbols {
pairs = append(pairs, symbols[x].BaseCurrency+"-"+symbols[x].QuoteCurrency)
pairs = append(pairs, fmt.Sprintf("%v%v%v", symbols[x].BaseCurrency, h.GetPairFormat(asset, false).Delimiter, symbols[x].QuoteCurrency))
}
return pairs, nil
}
@@ -214,25 +214,33 @@ func (h *HitBTC) UpdateTradablePairs(forceUpdate bool) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (h *HitBTC) UpdateTicker(currencyPair currency.Pair, assetType asset.Item) (ticker.Price, error) {
tick, err := h.GetTicker("")
var tickerPrice ticker.Price
tick, err := h.GetTickers()
if err != nil {
return ticker.Price{}, err
return tickerPrice, err
}
for _, x := range h.GetEnabledPairs(assetType) {
var tp ticker.Price
curr := h.FormatExchangeCurrency(x, assetType).String()
tp.Pair = x
tp.Ask = tick[curr].Ask
tp.Bid = tick[curr].Bid
tp.High = tick[curr].High
tp.Last = tick[curr].Last
tp.Low = tick[curr].Low
tp.Volume = tick[curr].Volume
err = ticker.ProcessTicker(h.GetName(), &tp, assetType)
if err != nil {
return ticker.Price{}, err
pairs := h.GetEnabledPairs(assetType)
for i := range pairs {
for j := range tick {
if !tick[j].Symbol.Equal(pairs[i]) {
continue
}
tickerPrice := ticker.Price{
Last: tick[j].Last,
High: tick[j].High,
Low: tick[j].Low,
Bid: tick[j].Bid,
Ask: tick[j].Ask,
Volume: tick[j].Volume,
QuoteVolume: tick[j].VolumeQuote,
Open: tick[j].Open,
Pair: pairs[i],
LastUpdated: tick[j].Timestamp,
}
err = ticker.ProcessTicker(h.GetName(), &tickerPrice, assetType)
if err != nil {
log.Error(log.Ticker, err)
}
}
}
return ticker.GetTicker(h.Name, currencyPair, assetType)

View File

@@ -32,6 +32,7 @@ const (
huobiMarketDetailMerged = "market/detail/merged"
huobiMarketDepth = "market/depth"
huobiMarketTrade = "market/trade"
huobiMarketTickers = "market/tickers"
huobiMarketTradeHistory = "market/history/trade"
huobiSymbols = "common/symbols"
huobiCurrencies = "common/currencys"
@@ -95,6 +96,13 @@ func (h *HUOBI) GetSpotKline(arg KlinesRequestParams) ([]KlineItem, error) {
return result.Data, err
}
// GetTickers returns the ticker for the specified symbol
func (h *HUOBI) GetTickers() (Tickers, error) {
var result Tickers
urlPath := fmt.Sprintf("%s/%s", h.API.Endpoints.URL, huobiMarketTickers)
return result, h.SendHTTPRequest(urlPath, &result)
}
// GetMarketDetailMerged returns the ticker for the specified symbol
func (h *HUOBI) GetMarketDetailMerged(symbol string) (DetailMerged, error) {
vals := url.Values{}

View File

@@ -170,6 +170,13 @@ func TestGetCurrencies(t *testing.T) {
}
}
func TestGetTicker(t *testing.T) {
_, err := h.GetTickers()
if err != nil {
t.Error(err)
}
}
func TestGetTimestamp(t *testing.T) {
t.Parallel()
_, err := h.GetTimestamp()

View File

@@ -19,7 +19,7 @@ type KlineItem struct {
Low float64 `json:"low"`
High float64 `json:"high"`
Amount float64 `json:"amount"`
Vol float64 `json:"vol"`
Volume float64 `json:"vol"`
Count int `json:"count"`
}
@@ -42,6 +42,23 @@ type DetailMerged struct {
Bid []float64 `json:"bid"`
}
// Tickers contain all tickers
type Tickers struct {
Data []Ticker `json:"data"`
}
// Ticker latest ticker data
type Ticker struct {
Amount float64 `json:"amount"`
Close float64 `json:"close"`
Count int64 `json:"count"`
High float64 `json:"high"`
Low float64 `json:"low"`
Open float64 `json:"open"`
Symbol currency.Pair `json:"symbol"`
Volume float64 `json:"vol"`
}
// OrderBookDataRequestParamsType var for request param types
type OrderBookDataRequestParamsType string
@@ -322,6 +339,22 @@ type WsKline struct {
}
}
type WsTick struct {
Channel string `json:"ch"`
Timestamp int64 `json:"ts"`
Tick struct {
Amount float64 `json:"amount"`
Close float64 `json:"close"`
Count float64 `json:"count"`
High float64 `json:"high"`
ID float64 `json:"id"`
Low float64 `json:"low"`
Open float64 `json:"open"`
Timestamp float64 `json:"ts"`
Volume float64 `json:"vol"`
} `json:"tick"`
}
// WsTrade defines market trade websocket response
type WsTrade struct {
Channel string `json:"ch"`

View File

@@ -23,10 +23,11 @@ import (
const (
baseWSURL = "wss://api.huobi.pro"
wsMarketURL = baseWSURL + "/ws"
wsMarketKline = "market.%s.kline.1min"
wsMarketDepth = "market.%s.depth.step0"
wsMarketTrade = "market.%s.trade.detail"
wsMarketURL = baseWSURL + "/ws"
wsMarketKline = "market.%s.kline.1min"
wsMarketDepth = "market.%s.depth.step0"
wsMarketTrade = "market.%s.trade.detail"
wsMarketTicker = "market.%s.detail"
wsAccountsOrdersEndPoint = "/ws/v1"
wsAccountsList = "accounts.list"
@@ -253,7 +254,7 @@ func (h *HUOBI) wsHandleMarketData(resp WsMessage) {
LowPrice: kline.Tick.Low,
Volume: kline.Tick.Volume,
}
case strings.Contains(init.Channel, "trade"):
case strings.Contains(init.Channel, "trade.detail"):
var trade WsTrade
err := common.JSONDecode(resp.Raw, &trade)
if err != nil {
@@ -267,6 +268,26 @@ func (h *HUOBI) wsHandleMarketData(resp WsMessage) {
CurrencyPair: currency.NewPairFromString(data[1]),
Timestamp: time.Unix(0, trade.Tick.Timestamp),
}
case strings.Contains(init.Channel, "detail"):
var ticker WsTick
err := common.JSONDecode(resp.Raw, &ticker)
if err != nil {
h.Websocket.DataHandler <- err
return
}
data := strings.Split(ticker.Channel, ".")
h.Websocket.DataHandler <- wshandler.TickerData{
Exchange: h.Name,
Open: ticker.Tick.Open,
Close: ticker.Tick.Close,
Volume: ticker.Tick.Amount,
QuoteVolume: ticker.Tick.Volume,
High: ticker.Tick.High,
Low: ticker.Tick.Low,
Timestamp: time.Unix(0, ticker.Timestamp),
AssetType: asset.Spot,
Pair: currency.NewPairFromString(data[1]),
}
}
}
@@ -303,7 +324,7 @@ func (h *HUOBI) WsProcessOrderbook(update *WsDepth, symbol string) error {
// GenerateDefaultSubscriptions Adds default subscriptions to websocket to be handled by ManageSubscriptions()
func (h *HUOBI) GenerateDefaultSubscriptions() {
var channels = []string{wsMarketKline, wsMarketDepth, wsMarketTrade}
var channels = []string{wsMarketKline, wsMarketDepth, wsMarketTrade, wsMarketTicker}
var subscriptions []wshandler.WebsocketChannelSubscription
if h.Websocket.CanUseAuthenticatedEndpoints() {
channels = append(channels, "orders.%v", "orders.%v.update")

View File

@@ -72,7 +72,7 @@ func (h *HUOBI) SetDefaults() {
Websocket: true,
RESTCapabilities: exchange.ProtocolFeatures{
AutoPairUpdates: true,
TickerBatching: false,
TickerBatching: true,
},
WithdrawPermissions: exchange.AutoWithdrawCryptoWithSetup |
exchange.NoFiatWithdrawals,
@@ -228,7 +228,7 @@ func (h *HUOBI) FetchTradablePairs(asset asset.Item) ([]string, error) {
var pairs []string
for x := range symbols {
pairs = append(pairs, symbols[x].BaseCurrency+"-"+symbols[x].QuoteCurrency)
pairs = append(pairs, fmt.Sprintf("%v%v%v", symbols[x].BaseCurrency, h.GetPairFormat(asset, false).Delimiter, symbols[x].QuoteCurrency))
}
return pairs, nil
@@ -248,28 +248,29 @@ func (h *HUOBI) UpdateTradablePairs(forceUpdate bool) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (h *HUOBI) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Price, error) {
var tickerPrice ticker.Price
tick, err := h.GetMarketDetailMerged(h.FormatExchangeCurrency(p, assetType).String())
tickers, err := h.GetTickers()
if err != nil {
return tickerPrice, err
}
tickerPrice.Pair = p
tickerPrice.Low = tick.Low
tickerPrice.Last = tick.Close
tickerPrice.Volume = tick.Volume
tickerPrice.High = tick.High
if len(tick.Ask) > 0 {
tickerPrice.Ask = tick.Ask[0]
}
if len(tick.Bid) > 0 {
tickerPrice.Bid = tick.Bid[0]
}
err = ticker.ProcessTicker(h.GetName(), &tickerPrice, assetType)
if err != nil {
return tickerPrice, err
pairs := h.GetEnabledPairs(assetType)
for i := range pairs {
for j := range tickers.Data {
if !pairs[i].Equal(tickers.Data[j].Symbol) {
continue
}
tickerPrice := ticker.Price{
High: tickers.Data[j].High,
Low: tickers.Data[j].Low,
Volume: tickers.Data[j].Volume,
Open: tickers.Data[j].Open,
Close: tickers.Data[j].Close,
Pair: tickers.Data[j].Symbol,
}
err = ticker.ProcessTicker(h.GetName(), &tickerPrice, assetType)
if err != nil {
log.Error(log.Ticker, err)
}
}
}
return ticker.GetTicker(h.Name, p, assetType)

View File

@@ -28,6 +28,7 @@ const (
huobihadaxMarketDetail = "market/detail"
huobihadaxMarketDetailMerged = "market/detail/merged"
huobihadaxMarketDepth = "market/depth"
huobihadaxMarketTicker = "market/tickers"
huobihadaxMarketTrade = "market/trade"
huobihadaxMarketTradeHistory = "market/history/trade"
huobihadaxSymbols = "common/symbols"
@@ -252,6 +253,13 @@ func (h *HUOBIHADAX) GetCurrencies() ([]string, error) {
return result.Currencies, err
}
// GetTickers returns the ticker for the specified symbol
func (h *HUOBIHADAX) GetTickers() (Tickers, error) {
var result Tickers
urlPath := fmt.Sprintf("%s/%s", h.API.Endpoints.URL, huobihadaxMarketTicker)
return result, h.SendHTTPRequest(urlPath, &result)
}
// GetTimestamp returns the Huobi server time
func (h *HUOBIHADAX) GetTimestamp() (int64, error) {
type response struct {

View File

@@ -215,6 +215,13 @@ func TestGetCurrencies(t *testing.T) {
}
}
func TestGetTicker(t *testing.T) {
_, err := h.GetTickers()
if err != nil {
t.Error(err)
}
}
func TestGetTimestamp(t *testing.T) {
t.Parallel()
_, err := h.GetTimestamp()

View File

@@ -21,10 +21,43 @@ type KlineItem struct {
Low float64 `json:"low"`
High float64 `json:"high"`
Amount float64 `json:"amount"`
Vol float64 `json:"vol"`
Volume float64 `json:"vol"`
Count int `json:"count"`
}
type WsTick struct {
Channel string `json:"ch"`
Timestamp int64 `json:"ts"`
Tick struct {
Amount float64 `json:"amount"`
Close float64 `json:"close"`
Count float64 `json:"count"`
High float64 `json:"high"`
ID float64 `json:"id"`
Low float64 `json:"low"`
Open float64 `json:"open"`
Timestamp float64 `json:"ts"`
Volume float64 `json:"vol"`
} `json:"tick"`
}
// Tickers contain all tickers
type Tickers struct {
Data []Ticker `json:"data"`
}
// Ticker latest ticker data
type Ticker struct {
Amount float64 `json:"amount"`
Close float64 `json:"close"`
Count int64 `json:"count"`
High float64 `json:"high"`
Low float64 `json:"low"`
Open float64 `json:"open"`
Symbol currency.Pair `json:"symbol"`
Volume float64 `json:"vol"`
}
// DetailMerged stores the ticker detail merged data
type DetailMerged struct {
Detail

View File

@@ -25,6 +25,7 @@ const (
wsMarketKline = "market.%s.kline.1min"
wsMarketDepth = "market.%s.depth.step0"
wsMarketTrade = "market.%s.trade.detail"
wsMarketTicker = "market.%s.detail"
wsAccountsOrdersBaseURL = "wss://api.huobi.pro"
wsAccountsOrdersEndPoint = "/ws/v1"
@@ -254,7 +255,7 @@ func (h *HUOBIHADAX) wsHandleMarketData(resp WsMessage) {
LowPrice: kline.Tick.Low,
Volume: kline.Tick.Volume,
}
case strings.Contains(init.Channel, "trade"):
case strings.Contains(init.Channel, "trade.detail"):
var trade WsTrade
err := common.JSONDecode(resp.Raw, &trade)
if err != nil {
@@ -268,6 +269,26 @@ func (h *HUOBIHADAX) wsHandleMarketData(resp WsMessage) {
CurrencyPair: currency.NewPairFromString(data[1]),
Timestamp: time.Unix(0, trade.Tick.Timestamp),
}
case strings.Contains(init.Channel, "detail"):
var ticker WsTick
err := common.JSONDecode(resp.Raw, &ticker)
if err != nil {
h.Websocket.DataHandler <- err
return
}
data := strings.Split(ticker.Channel, ".")
h.Websocket.DataHandler <- wshandler.TickerData{
Exchange: h.Name,
Open: ticker.Tick.Open,
Close: ticker.Tick.Close,
Volume: ticker.Tick.Amount,
QuoteVolume: ticker.Tick.Volume,
High: ticker.Tick.High,
Low: ticker.Tick.Low,
Timestamp: time.Unix(0, ticker.Timestamp),
AssetType: asset.Spot,
Pair: currency.NewPairFromString(data[1]),
}
}
}
@@ -304,7 +325,7 @@ func (h *HUOBIHADAX) WsProcessOrderbook(update *WsDepth, symbol string) error {
// GenerateDefaultSubscriptions Adds default subscriptions to websocket to be handled by ManageSubscriptions()
func (h *HUOBIHADAX) GenerateDefaultSubscriptions() {
var channels = []string{wsMarketKline, wsMarketDepth, wsMarketTrade}
var channels = []string{wsMarketKline, wsMarketDepth, wsMarketTrade, wsMarketTicker}
var subscriptions []wshandler.WebsocketChannelSubscription
if h.Websocket.CanUseAuthenticatedEndpoints() {
channels = append(channels, "orders.%v", "orders.%v.update")

View File

@@ -72,7 +72,7 @@ func (h *HUOBIHADAX) SetDefaults() {
Websocket: true,
RESTCapabilities: exchange.ProtocolFeatures{
AutoPairUpdates: true,
TickerBatching: false,
TickerBatching: true,
},
WithdrawPermissions: exchange.AutoWithdrawCryptoWithSetup |
exchange.NoFiatWithdrawals,
@@ -191,7 +191,7 @@ func (h *HUOBIHADAX) FetchTradablePairs(asset asset.Item) ([]string, error) {
var pairs []string
for x := range symbols {
pairs = append(pairs, symbols[x].BaseCurrency+"-"+symbols[x].QuoteCurrency)
pairs = append(pairs, fmt.Sprintf("%v%v%v", symbols[x].BaseCurrency, h.GetPairFormat(asset, false).Delimiter, symbols[x].QuoteCurrency))
}
return pairs, nil
@@ -211,28 +211,29 @@ func (h *HUOBIHADAX) UpdateTradablePairs(forceUpdate bool) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (h *HUOBIHADAX) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Price, error) {
var tickerPrice ticker.Price
tick, err := h.GetMarketDetailMerged(h.FormatExchangeCurrency(p, assetType).String())
tickers, err := h.GetTickers()
if err != nil {
return tickerPrice, err
}
tickerPrice.Pair = p
tickerPrice.Low = tick.Low
tickerPrice.Last = tick.Close
tickerPrice.Volume = tick.Volume
tickerPrice.High = tick.High
if len(tick.Ask) > 0 {
tickerPrice.Ask = tick.Ask[0]
}
if len(tick.Bid) > 0 {
tickerPrice.Bid = tick.Bid[0]
}
err = ticker.ProcessTicker(h.GetName(), &tickerPrice, assetType)
if err != nil {
return tickerPrice, err
pairs := h.GetEnabledPairs(assetType)
for i := range pairs {
for j := range tickers.Data {
if !pairs[i].Equal(tickers.Data[j].Symbol) {
continue
}
tickerPrice := ticker.Price{
High: tickers.Data[j].High,
Low: tickers.Data[j].Low,
Volume: tickers.Data[j].Volume,
Open: tickers.Data[j].Open,
Close: tickers.Data[j].Close,
Pair: tickers.Data[j].Symbol,
}
err = ticker.ProcessTicker(h.GetName(), &tickerPrice, assetType)
if err != nil {
log.Error(log.Ticker, err)
}
}
}
return ticker.GetTicker(h.Name, p, assetType)

View File

@@ -1,5 +1,7 @@
package itbit
import "time"
// GeneralReturn is a generalized return type to capture any errors
type GeneralReturn struct {
Code int `json:"code"`
@@ -9,23 +11,23 @@ type GeneralReturn struct {
// Ticker holds returned ticker information
type Ticker struct {
Pair string `json:"pair"`
Bid float64 `json:"bid,string"`
BidAmt float64 `json:"bidAmt,string"`
Ask float64 `json:"ask,string"`
AskAmt float64 `json:"askAmt,string"`
LastPrice float64 `json:"lastPrice,string"`
LastAmt float64 `json:"lastAmt,string"`
Volume24h float64 `json:"volume24h,string"`
VolumeToday float64 `json:"volumeToday,string"`
High24h float64 `json:"high24h,string"`
Low24h float64 `json:"low24h,string"`
HighToday float64 `json:"highToday,string"`
LowToday float64 `json:"lowToday,string"`
OpenToday float64 `json:"openToday,string"`
VwapToday float64 `json:"vwapToday,string"`
Vwap24h float64 `json:"vwap24h,string"`
ServertimeUTC string `json:"serverTimeUTC"`
Pair string `json:"pair"`
Bid float64 `json:"bid,string"`
BidAmt float64 `json:"bidAmt,string"`
Ask float64 `json:"ask,string"`
AskAmt float64 `json:"askAmt,string"`
LastPrice float64 `json:"lastPrice,string"`
LastAmt float64 `json:"lastAmt,string"`
Volume24h float64 `json:"volume24h,string"`
VolumeToday float64 `json:"volumeToday,string"`
High24h float64 `json:"high24h,string"`
Low24h float64 `json:"low24h,string"`
HighToday float64 `json:"highToday,string"`
LowToday float64 `json:"lowToday,string"`
OpenToday float64 `json:"openToday,string"`
VwapToday float64 `json:"vwapToday,string"`
Vwap24h float64 `json:"vwap24h,string"`
ServertimeUTC time.Time `json:"serverTimeUTC"`
}
// OrderbookResponse contains multi-arrayed strings of bid and ask side

View File

@@ -133,15 +133,17 @@ func (i *ItBit) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Pric
if err != nil {
return tickerPrice, err
}
tickerPrice.Pair = p
tickerPrice.Ask = tick.Ask
tickerPrice.Bid = tick.Bid
tickerPrice.Last = tick.LastPrice
tickerPrice.High = tick.High24h
tickerPrice.Low = tick.Low24h
tickerPrice.Volume = tick.Volume24h
tickerPrice = ticker.Price{
Last: tick.LastPrice,
High: tick.High24h,
Low: tick.Low24h,
Bid: tick.Bid,
Ask: tick.Ask,
Volume: tick.Volume24h,
Open: tick.OpenToday,
Pair: p,
LastUpdated: tick.ServertimeUTC,
}
err = ticker.ProcessTicker(i.GetName(), &tickerPrice, assetType)
if err != nil {
return tickerPrice, err

View File

@@ -51,6 +51,8 @@ const (
krakenUnauthRate = 0
)
var assetPairMap map[string]string
// Kraken is the overarching type across the alphapoint package
type Kraken struct {
exchange.Base
@@ -102,6 +104,12 @@ func (k *Kraken) GetAssetPairs() (map[string]AssetPairs, error) {
if err := k.SendHTTPRequest(path, &response); err != nil {
return response.Result, err
}
for i := range response.Result {
if assetPairMap == nil {
assetPairMap = make(map[string]string)
}
assetPairMap[i] = response.Result[i].Altname
}
return response.Result, GetError(response.Error)
}
@@ -134,7 +142,7 @@ func (k *Kraken) GetTicker(symbol string) (Ticker, error) {
tick.Bid, _ = strconv.ParseFloat(resp.Data[i].Bid[0], 64)
tick.Last, _ = strconv.ParseFloat(resp.Data[i].Last[0], 64)
tick.Volume, _ = strconv.ParseFloat(resp.Data[i].Volume[1], 64)
tick.VWAP, _ = strconv.ParseFloat(resp.Data[i].VWAP[1], 64)
tick.VolumeWeightedAveragePrice, _ = strconv.ParseFloat(resp.Data[i].VolumeWeightedAveragePrice[1], 64)
tick.Trades = resp.Data[i].Trades[1]
tick.Low, _ = strconv.ParseFloat(resp.Data[i].Low[1], 64)
tick.High, _ = strconv.ParseFloat(resp.Data[i].High[1], 64)
@@ -175,7 +183,7 @@ func (k *Kraken) GetTickers(pairList string) (Tickers, error) {
tick.Bid, _ = strconv.ParseFloat(resp.Data[i].Bid[0], 64)
tick.Last, _ = strconv.ParseFloat(resp.Data[i].Last[0], 64)
tick.Volume, _ = strconv.ParseFloat(resp.Data[i].Volume[1], 64)
tick.VWAP, _ = strconv.ParseFloat(resp.Data[i].VWAP[1], 64)
tick.VolumeWeightedAveragePrice, _ = strconv.ParseFloat(resp.Data[i].VolumeWeightedAveragePrice[1], 64)
tick.Trades = resp.Data[i].Trades[1]
tick.Low, _ = strconv.ParseFloat(resp.Data[i].Low[1], 64)
tick.High, _ = strconv.ParseFloat(resp.Data[i].High[1], 64)
@@ -224,7 +232,7 @@ func (k *Kraken) GetOHLC(symbol string) ([]OpenHighLowClose, error) {
case 4:
o.Close, _ = strconv.ParseFloat(x.(string), 64)
case 5:
o.Vwap, _ = strconv.ParseFloat(x.(string), 64)
o.VolumeWeightedAveragePrice, _ = strconv.ParseFloat(x.(string), 64)
case 6:
o.Volume, _ = strconv.ParseFloat(x.(string), 64)
case 7:
@@ -767,8 +775,8 @@ func (k *Kraken) AddOrder(symbol, side, orderType string, volume, price, price2,
params.Set("leverage", strconv.FormatFloat(leverage, 'f', -1, 64))
}
if args.Oflags != "" {
params.Set("oflags", args.Oflags)
if args.OrderFlags != "" {
params.Set("oflags", args.OrderFlags)
}
if args.StartTm != "" {

View File

@@ -235,7 +235,7 @@ func TestGetTradeVolume(t *testing.T) {
// TestAddOrder API endpoint test
func TestAddOrder(t *testing.T) {
t.Parallel()
args := AddOrderOptions{Oflags: "fcib"}
args := AddOrderOptions{OrderFlags: "fcib"}
_, err := k.AddOrder("XXBTZUSD",
exchange.SellOrderSide.ToLower().ToString(), exchange.LimitOrderType.ToLower().ToString(),
0.00000001, 0, 0, 0, &args)

View File

@@ -38,15 +38,15 @@ type AssetPairs struct {
// Ticker is a standard ticker type
type Ticker struct {
Ask float64
Bid float64
Last float64
Volume float64
VWAP float64
Trades int64
Low float64
High float64
Open float64
Ask float64
Bid float64
Last float64
Volume float64
VolumeWeightedAveragePrice float64
Trades int64
Low float64
High float64
Open float64
}
// Tickers stores a map of tickers
@@ -54,27 +54,27 @@ type Tickers map[string]Ticker
// TickerResponse holds ticker information before its put into the Ticker struct
type TickerResponse struct {
Ask []string `json:"a"`
Bid []string `json:"b"`
Last []string `json:"c"`
Volume []string `json:"v"`
VWAP []string `json:"p"`
Trades []int64 `json:"t"`
Low []string `json:"l"`
High []string `json:"h"`
Open string `json:"o"`
Ask []string `json:"a"`
Bid []string `json:"b"`
Last []string `json:"c"`
Volume []string `json:"v"`
VolumeWeightedAveragePrice []string `json:"p"`
Trades []int64 `json:"t"`
Low []string `json:"l"`
High []string `json:"h"`
Open string `json:"o"`
}
// OpenHighLowClose contains ticker event information
type OpenHighLowClose struct {
Time float64
Open float64
High float64
Low float64
Close float64
Vwap float64
Volume float64
Count float64
Time float64
Open float64
High float64
Low float64
Close float64
VolumeWeightedAveragePrice float64
Volume float64
Count float64
}
// RecentTrades holds recent trade data
@@ -125,13 +125,13 @@ type TradeBalanceInfo struct {
// OrderInfo type
type OrderInfo struct {
RefID string `json:"refid"`
UserRef int32 `json:"userref"`
Status string `json:"status"`
OpenTm float64 `json:"opentm"`
StartTm float64 `json:"starttm"`
ExpireTm float64 `json:"expiretm"`
Descr struct {
RefID string `json:"refid"`
UserRef int32 `json:"userref"`
Status string `json:"status"`
OpenTime float64 `json:"opentm"`
StartTime float64 `json:"starttm"`
ExpireTime float64 `json:"expiretm"`
Description struct {
Pair string `json:"pair"`
Type string `json:"type"`
OrderType string `json:"ordertype"`
@@ -141,16 +141,16 @@ type OrderInfo struct {
Order string `json:"order"`
Close string `json:"close"`
} `json:"descr"`
Vol float64 `json:"vol,string"`
VolExec float64 `json:"vol_exec,string"`
Cost float64 `json:"cost,string"`
Fee float64 `json:"fee,string"`
Price float64 `json:"price,string"`
StopPrice float64 `json:"stopprice,string"`
LimitPrice float64 `json:"limitprice,string"`
Misc string `json:"misc"`
Oflags string `json:"oflags"`
Trades []string `json:"trades"`
Volume float64 `json:"vol,string"`
VolumeExecuted float64 `json:"vol_exec,string"`
Cost float64 `json:"cost,string"`
Fee float64 `json:"fee,string"`
Price float64 `json:"price,string"`
StopPrice float64 `json:"stopprice,string"`
LimitPrice float64 `json:"limitprice,string"`
Misc string `json:"misc"`
OrderFlags string `json:"oflags"`
Trades []string `json:"trades"`
}
// OpenOrders type
@@ -198,44 +198,44 @@ type TradesHistory struct {
// TradeInfo type
type TradeInfo struct {
OrderTxID string `json:"ordertxid"`
Pair string `json:"pair"`
Time float64 `json:"time"`
Type string `json:"type"`
OrderType string `json:"ordertype"`
Price float64 `json:"price,string"`
Cost float64 `json:"cost,string"`
Fee float64 `json:"fee,string"`
Vol float64 `json:"vol,string"`
Margin float64 `json:"margin,string"`
Misc string `json:"misc"`
PosTxID string `json:"postxid"`
Cprice float64 `json:"cprice,string"`
Cfee float64 `json:"cfee,string"`
Cvol float64 `json:"cvol,string"`
Cmargin float64 `json:"cmargin,string"`
Trades []string `json:"trades"`
PosStatus string `json:"posstatus"`
OrderTxID string `json:"ordertxid"`
Pair string `json:"pair"`
Time float64 `json:"time"`
Type string `json:"type"`
OrderType string `json:"ordertype"`
Price float64 `json:"price,string"`
Cost float64 `json:"cost,string"`
Fee float64 `json:"fee,string"`
Volume float64 `json:"vol,string"`
Margin float64 `json:"margin,string"`
Misc string `json:"misc"`
PosTxID string `json:"postxid"`
ClosedPositionAveragePrice float64 `json:"cprice,string"`
ClosedPositionFee float64 `json:"cfee,string"`
ClosedPositionVolume float64 `json:"cvol,string"`
ClosedPositionMargin float64 `json:"cmargin,string"`
Trades []string `json:"trades"`
PosStatus string `json:"posstatus"`
}
// Position holds the opened position
type Position struct {
Ordertxid string `json:"ordertxid"`
Pair string `json:"pair"`
Time float64 `json:"time"`
Type string `json:"type"`
OrderType string `json:"ordertype"`
Cost float64 `json:"cost,string"`
Fee float64 `json:"fee,string"`
Vol float64 `json:"vol,string"`
VolClosed float64 `json:"vol_closed,string"`
Margin float64 `json:"margin,string"`
Rollovertm int64 `json:"rollovertm,string"`
Misc string `json:"misc"`
Oflags string `json:"oflags"`
PosStatus string `json:"posstatus"`
Net string `json:"net"`
Terms string `json:"terms"`
Ordertxid string `json:"ordertxid"`
Pair string `json:"pair"`
Time float64 `json:"time"`
Type string `json:"type"`
OrderType string `json:"ordertype"`
Cost float64 `json:"cost,string"`
Fee float64 `json:"fee,string"`
Volume float64 `json:"vol,string"`
VolumeClosed float64 `json:"vol_closed,string"`
Margin float64 `json:"margin,string"`
RolloverTime int64 `json:"rollovertm,string"`
Misc string `json:"misc"`
OrderFlags string `json:"oflags"`
PositionStatus string `json:"posstatus"`
Net string `json:"net"`
Terms string `json:"terms"`
}
// GetLedgersOptions type
@@ -314,7 +314,7 @@ type OrderDescription struct {
// AddOrderOptions represents the AddOrder options
type AddOrderOptions struct {
UserRef int32
Oflags string
OrderFlags string
StartTm string
ExpireTm string
CloseOrderType string

View File

@@ -241,6 +241,8 @@ func getSubscriptionChannelData(id int64) WebsocketChannelData {
// wsProcessTickers converts ticker data and sends it to the datahandler
func (k *Kraken) wsProcessTickers(channelData *WebsocketChannelData, data interface{}) {
tickerData := data.(map[string]interface{})
askData := tickerData["a"].([]interface{})
bidData := tickerData["b"].([]interface{})
closeData := tickerData["c"].([]interface{})
openData := tickerData["o"].([]interface{})
lowData := tickerData["l"].([]interface{})
@@ -251,17 +253,21 @@ func (k *Kraken) wsProcessTickers(channelData *WebsocketChannelData, data interf
highPrice, _ := strconv.ParseFloat(highData[0].(string), 64)
lowPrice, _ := strconv.ParseFloat(lowData[0].(string), 64)
quantity, _ := strconv.ParseFloat(volumeData[0].(string), 64)
ask, _ := strconv.ParseFloat(askData[0].(string), 64)
bid, _ := strconv.ParseFloat(bidData[0].(string), 64)
k.Websocket.DataHandler <- wshandler.TickerData{
Timestamp: time.Now(),
Exchange: k.Name,
AssetType: asset.Spot,
Pair: channelData.Pair,
ClosePrice: closePrice,
OpenPrice: openPrice,
HighPrice: highPrice,
LowPrice: lowPrice,
Quantity: quantity,
Exchange: k.Name,
Open: openPrice,
Close: closePrice,
Volume: quantity,
High: highPrice,
Low: lowPrice,
Bid: bid,
Ask: ask,
Timestamp: time.Now(),
AssetType: asset.Spot,
Pair: channelData.Pair,
}
}

View File

@@ -62,8 +62,9 @@ func (k *Kraken) SetDefaults() {
Separator: ",",
},
ConfigFormat: &currency.PairFormat{
Delimiter: "-",
Uppercase: true,
Delimiter: "-",
Separator: ",",
},
}
@@ -167,9 +168,9 @@ func (k *Kraken) Run() {
}
forceUpdate := false
if !common.StringDataContains(k.GetEnabledPairs(asset.Spot).Strings(), "-") ||
!common.StringDataContains(k.GetAvailablePairs(asset.Spot).Strings(), "-") {
enabledPairs := currency.NewPairsFromStrings([]string{"XBT-USD"})
if !common.StringDataContains(k.GetEnabledPairs(asset.Spot).Strings(), k.GetPairFormat(asset.Spot, false).Delimiter) ||
!common.StringDataContains(k.GetAvailablePairs(asset.Spot).Strings(), k.GetPairFormat(asset.Spot, false).Delimiter) {
enabledPairs := currency.NewPairsFromStrings([]string{fmt.Sprintf("BTC%vUSD", k.GetPairFormat(asset.Spot, false).Delimiter)})
log.Warn(log.ExchangeSys, "Available pairs for Kraken reset due to config upgrade, please enable the ones you would like again")
forceUpdate = true
@@ -210,7 +211,7 @@ func (k *Kraken) FetchTradablePairs(asset asset.Item) ([]string, error) {
if v.Quote[0] == 'Z' || v.Quote[0] == 'X' {
v.Quote = v.Quote[1:]
}
products = append(products, v.Base+"-"+v.Quote)
products = append(products, fmt.Sprintf("%v%v%v", v.Base, k.GetPairFormat(asset, false).Delimiter, v.Quote))
}
return products, nil
}
@@ -239,21 +240,33 @@ func (k *Kraken) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Pri
return tickerPrice, err
}
for _, x := range pairs {
for y, z := range tickers {
if !strings.Contains(y, x.Base.Upper().String()) ||
!strings.Contains(y, x.Quote.Upper().String()) {
continue
for i := range pairs {
for curr, v := range tickers {
if !strings.EqualFold(pairs[i].String(), curr) {
var altCurrency string
var ok bool
if altCurrency, ok = assetPairMap[curr]; !ok {
continue
}
if !strings.EqualFold(pairs[i].String(), altCurrency) {
continue
}
}
tickerPrice = ticker.Price{
Last: v.Last,
High: v.High,
Low: v.Low,
Bid: v.Bid,
Ask: v.Ask,
Volume: v.Volume,
Open: v.Open,
Pair: pairs[i],
}
err = ticker.ProcessTicker(k.Name, &tickerPrice, assetType)
if err != nil {
log.Error(log.Ticker, err)
}
var tp ticker.Price
tp.Pair = x
tp.Last = z.Last
tp.Ask = z.Ask
tp.Bid = z.Bid
tp.High = z.High
tp.Low = z.Low
tp.Volume = z.Volume
ticker.ProcessTicker(k.GetName(), &tp, assetType)
}
}
return ticker.GetTicker(k.GetName(), p, assetType)
@@ -473,19 +486,19 @@ func (k *Kraken) GetActiveOrders(getOrdersRequest *exchange.GetOrdersRequest) ([
var orders []exchange.OrderDetail
for i := range resp.Open {
symbol := currency.NewPairFromString(resp.Open[i].Descr.Pair)
orderDate := time.Unix(int64(resp.Open[i].StartTm), 0)
side := exchange.OrderSide(strings.ToUpper(resp.Open[i].Descr.Type))
orderType := exchange.OrderType(strings.ToUpper(resp.Open[i].Descr.OrderType))
symbol := currency.NewPairFromString(resp.Open[i].Description.Pair)
orderDate := time.Unix(int64(resp.Open[i].StartTime), 0)
side := exchange.OrderSide(strings.ToUpper(resp.Open[i].Description.Type))
orderType := exchange.OrderType(strings.ToUpper(resp.Open[i].Description.OrderType))
orders = append(orders, exchange.OrderDetail{
ID: i,
Amount: resp.Open[i].Vol,
RemainingAmount: (resp.Open[i].Vol - resp.Open[i].VolExec),
ExecutedAmount: resp.Open[i].VolExec,
Amount: resp.Open[i].Volume,
RemainingAmount: (resp.Open[i].Volume - resp.Open[i].VolumeExecuted),
ExecutedAmount: resp.Open[i].VolumeExecuted,
Exchange: k.Name,
OrderDate: orderDate,
Price: resp.Open[i].Descr.Price,
Price: resp.Open[i].Description.Price,
OrderSide: side,
OrderType: orderType,
CurrencyPair: symbol,
@@ -517,19 +530,19 @@ func (k *Kraken) GetOrderHistory(getOrdersRequest *exchange.GetOrdersRequest) ([
var orders []exchange.OrderDetail
for i := range resp.Closed {
symbol := currency.NewPairFromString(resp.Closed[i].Descr.Pair)
orderDate := time.Unix(int64(resp.Closed[i].StartTm), 0)
side := exchange.OrderSide(strings.ToUpper(resp.Closed[i].Descr.Type))
orderType := exchange.OrderType(strings.ToUpper(resp.Closed[i].Descr.OrderType))
symbol := currency.NewPairFromString(resp.Closed[i].Description.Pair)
orderDate := time.Unix(int64(resp.Closed[i].StartTime), 0)
side := exchange.OrderSide(strings.ToUpper(resp.Closed[i].Description.Type))
orderType := exchange.OrderType(strings.ToUpper(resp.Closed[i].Description.OrderType))
orders = append(orders, exchange.OrderDetail{
ID: i,
Amount: resp.Closed[i].Vol,
RemainingAmount: (resp.Closed[i].Vol - resp.Closed[i].VolExec),
ExecutedAmount: resp.Closed[i].VolExec,
Amount: resp.Closed[i].Volume,
RemainingAmount: (resp.Closed[i].Volume - resp.Closed[i].VolumeExecuted),
ExecutedAmount: resp.Closed[i].VolumeExecuted,
Exchange: k.Name,
OrderDate: orderDate,
Price: resp.Closed[i].Descr.Price,
Price: resp.Closed[i].Description.Price,
OrderSide: side,
OrderType: orderType,
CurrencyPair: symbol,

View File

@@ -239,13 +239,12 @@ func (l *LakeBTC) processTicker(ticker string) error {
continue
}
l.Websocket.DataHandler <- wshandler.TickerData{
Timestamp: time.Now(),
Pair: currency.NewPairFromString(k),
Exchange: l.Name,
Volume: vol,
High: high,
Low: low,
AssetType: asset.Spot,
Exchange: l.GetName(),
Quantity: vol,
HighPrice: high,
LowPrice: low,
Pair: currency.NewPairFromString(k),
}
}
return nil

View File

@@ -186,25 +186,29 @@ func (l *LakeBTC) UpdateTradablePairs(forceUpdate bool) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (l *LakeBTC) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Price, error) {
tick, err := l.GetTicker()
ticks, err := l.GetTicker()
if err != nil {
return ticker.Price{}, err
}
for _, x := range l.GetEnabledPairs(assetType) {
currency := l.FormatExchangeCurrency(x, assetType).String()
pairs := l.GetEnabledPairs(assetType)
for i := range pairs {
currency := l.FormatExchangeCurrency(pairs[i], assetType).String()
if _, ok := ticks[currency]; !ok {
continue
}
var tickerPrice ticker.Price
tickerPrice.Pair = x
tickerPrice.Ask = tick[currency].Ask
tickerPrice.Bid = tick[currency].Bid
tickerPrice.Volume = tick[currency].Volume
tickerPrice.High = tick[currency].High
tickerPrice.Low = tick[currency].Low
tickerPrice.Last = tick[currency].Last
tickerPrice.Pair = pairs[i]
tickerPrice.Ask = ticks[currency].Ask
tickerPrice.Bid = ticks[currency].Bid
tickerPrice.Volume = ticks[currency].Volume
tickerPrice.High = ticks[currency].High
tickerPrice.Low = ticks[currency].Low
tickerPrice.Last = ticks[currency].Last
err = ticker.ProcessTicker(l.GetName(), &tickerPrice, assetType)
if err != nil {
return tickerPrice, err
log.Error(log.Ticker, err)
}
}
return ticker.GetTicker(l.Name, p, assetType)

View File

@@ -68,6 +68,15 @@ func (l *Lbank) GetTicker(symbol string) (TickerResponse, error) {
return t, l.SendHTTPRequest(path, &t)
}
// GetTickers returns all tickers
func (l *Lbank) GetTickers() ([]TickerResponse, error) {
var t []TickerResponse
params := url.Values{}
params.Set("symbol", "all")
path := fmt.Sprintf("%s/v%s/%s?%s", l.API.Endpoints.URL, lbankAPIVersion, lbankTicker, params.Encode())
return t, l.SendHTTPRequest(path, &t)
}
// GetCurrencyPairs returns a list of supported currency pairs by the exchange
func (l *Lbank) GetCurrencyPairs() ([]string, error) {
path := fmt.Sprintf("%s/v%s/%s", l.API.Endpoints.URL, lbankAPIVersion,

View File

@@ -59,6 +59,17 @@ func TestGetTicker(t *testing.T) {
}
}
func TestGetTickers(t *testing.T) {
TestSetup(t)
tickers, err := l.GetTickers()
if err != nil {
t.Errorf("test failed: %v", err)
}
if len(tickers) <= 1 {
t.Errorf("Expected multiple tickers, received %v", len(tickers))
}
}
func TestGetCurrencyPairs(t *testing.T) {
TestSetup(t)
_, err := l.GetCurrencyPairs()

View File

@@ -2,6 +2,8 @@ package lbank
import (
"encoding/json"
"github.com/thrasher-corp/gocryptotrader/currency"
)
// Ticker stores the ticker price data for a currency pair
@@ -16,9 +18,9 @@ type Ticker struct {
// TickerResponse stores the ticker price data and timestamp for a currency pair
type TickerResponse struct {
Symbol string `json:"symbol"`
Timestamp int64 `json:"timestamp"`
Ticker Ticker `json:"ticker"`
Symbol currency.Pair `json:"symbol"`
Timestamp int64 `json:"timestamp"`
Ticker Ticker `json:"ticker"`
}
// MarketDepthResponse stores arrays for asks, bids and a timestamp for a currecy pair

View File

@@ -69,6 +69,7 @@ func (l *Lbank) SetDefaults() {
REST: true,
RESTCapabilities: exchange.ProtocolFeatures{
AutoPairUpdates: true,
TickerBatching: true,
},
WithdrawPermissions: exchange.AutoWithdrawCryptoWithAPIPermission |
exchange.NoFiatWithdrawals,
@@ -157,21 +158,30 @@ func (l *Lbank) UpdateTradablePairs(forceUpdate bool) error {
// UpdateTicker updates and returns the ticker for a currency pair
func (l *Lbank) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Price, error) {
var tickerPrice ticker.Price
tickerInfo, err := l.GetTicker(l.FormatExchangeCurrency(p, assetType).String())
tickerInfo, err := l.GetTickers()
if err != nil {
return tickerPrice, err
}
tickerPrice.Pair = p
tickerPrice.Last = tickerInfo.Ticker.Latest
tickerPrice.High = tickerInfo.Ticker.High
tickerPrice.Volume = tickerInfo.Ticker.Volume
tickerPrice.Low = tickerInfo.Ticker.Low
err = ticker.ProcessTicker(l.GetName(), &tickerPrice, assetType)
if err != nil {
return tickerPrice, err
pairs := l.GetEnabledPairs(assetType)
for i := range pairs {
for j := range tickerInfo {
if !pairs[i].Equal(tickerInfo[j].Symbol) {
continue
}
tickerPrice = ticker.Price{
Last: tickerInfo[j].Ticker.Latest,
High: tickerInfo[j].Ticker.High,
Low: tickerInfo[j].Ticker.Low,
Volume: tickerInfo[j].Ticker.Volume,
Pair: tickerInfo[j].Symbol,
LastUpdated: time.Unix(0, tickerInfo[j].Timestamp),
}
err = ticker.ProcessTicker(l.GetName(), &tickerPrice, assetType)
if err != nil {
log.Error(log.Ticker, err)
}
}
}
return ticker.GetTicker(l.Name, p, assetType)
}

View File

@@ -312,7 +312,8 @@ type WalletBalanceInfo struct {
// Ticker contains ticker information
type Ticker struct {
Avg12h float64 `json:"avg_12h,string"`
Avg1h float64 `json:"avg_1h,string"`
Avg1h float64 `json:"avg_1h,string,omitempty"`
Avg6h float64 `json:"avg_6h,string,omitempty"`
Avg24h float64 `json:"avg_24h,string"`
Rates struct {
Last float64 `json:"last,string"`

View File

@@ -160,16 +160,20 @@ func (l *LocalBitcoins) UpdateTicker(p currency.Pair, assetType asset.Item) (tic
return tickerPrice, err
}
for _, x := range l.GetEnabledPairs(assetType) {
currency := x.Quote.String()
pairs := l.GetEnabledPairs(assetType)
for i := range pairs {
curr := pairs[i].Quote.String()
if _, ok := tick[curr]; !ok {
continue
}
var tp ticker.Price
tp.Pair = x
tp.Last = tick[currency].Avg24h
tp.Volume = tick[currency].VolumeBTC
tp.Pair = pairs[i]
tp.Last = tick[curr].Avg24h
tp.Volume = tick[curr].VolumeBTC
err = ticker.ProcessTicker(l.GetName(), &tp, assetType)
if err != nil {
return tickerPrice, err
log.Error(log.Ticker, err)
}
}

View File

@@ -1,6 +1,7 @@
package okcoin
import (
"fmt"
"sync"
"time"
@@ -10,6 +11,7 @@ import (
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
"github.com/thrasher-corp/gocryptotrader/exchanges/websocket/wshandler"
log "github.com/thrasher-corp/gocryptotrader/logger"
)
@@ -57,13 +59,13 @@ func (o *OKCoin) SetDefaults() {
UseGlobalFormat: true,
RequestFormat: &currency.PairFormat{
Uppercase: false,
Delimiter: "_",
Uppercase: true,
Delimiter: "-",
},
ConfigFormat: &currency.PairFormat{
Uppercase: true,
Delimiter: "_",
Delimiter: "-",
},
}
@@ -73,7 +75,7 @@ func (o *OKCoin) SetDefaults() {
Websocket: true,
RESTCapabilities: exchange.ProtocolFeatures{
AutoPairUpdates: true,
TickerBatching: false,
TickerBatching: true,
},
WithdrawPermissions: exchange.AutoWithdrawCrypto |
exchange.NoFiatWithdrawals,
@@ -122,6 +124,28 @@ func (o *OKCoin) Run() {
log.Debugf(log.ExchangeSys, "%s Websocket: %s. (url: %s).\n", o.GetName(), common.IsEnabled(o.Websocket.IsEnabled()), o.WebsocketURL)
}
if o.Config.CurrencyPairs.ConfigFormat.Delimiter != o.CurrencyPairs.ConfigFormat.Delimiter {
o.Config.CurrencyPairs.ConfigFormat.Delimiter = o.CurrencyPairs.ConfigFormat.Delimiter
}
if o.Config.CurrencyPairs.RequestFormat.Uppercase != o.CurrencyPairs.RequestFormat.Uppercase {
o.Config.CurrencyPairs.RequestFormat.Uppercase = true
}
if o.Config.CurrencyPairs.RequestFormat.Delimiter != o.CurrencyPairs.RequestFormat.Delimiter {
o.Config.CurrencyPairs.RequestFormat.Delimiter = o.CurrencyPairs.RequestFormat.Delimiter
}
if !common.StringDataContains(o.Config.CurrencyPairs.Pairs[asset.Spot].Enabled.Strings(), o.CurrencyPairs.RequestFormat.Delimiter) {
enabledPairs := currency.NewPairsFromStrings([]string{"BTC-USD"})
log.Warnf(log.ExchangeSys,
"Enabled pairs for %v reset due to config upgrade, please enable the ones you would like again.", o.Name)
err := o.UpdatePairs(enabledPairs, asset.Spot, true, true)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to update currencies.\n", o.GetName())
return
}
}
if !o.GetEnabledFeatures().AutoPairUpdates {
return
}
@@ -141,7 +165,7 @@ func (o *OKCoin) FetchTradablePairs(asset asset.Item) ([]string, error) {
var pairs []string
for x := range prods {
pairs = append(pairs, prods[x].BaseCurrency+"_"+prods[x].QuoteCurrency)
pairs = append(pairs, fmt.Sprintf("%v%v%v", prods[x].BaseCurrency, o.GetPairFormat(asset, false).Delimiter, prods[x].QuoteCurrency))
}
return pairs, nil
@@ -158,3 +182,48 @@ func (o *OKCoin) UpdateTradablePairs(forceUpdate bool) error {
return o.UpdatePairs(currency.NewPairsFromStrings(pairs),
asset.Spot, false, forceUpdate)
}
// UpdateTicker updates and returns the ticker for a currency pair
func (o *OKCoin) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Price, error) {
var tickerData ticker.Price
if assetType == asset.Spot {
resp, err := o.GetSpotAllTokenPairsInformation()
if err != nil {
return tickerData, err
}
pairs := o.GetEnabledPairs(assetType)
for i := range pairs {
for j := range resp {
if !pairs[i].Equal(resp[j].InstrumentID) {
continue
}
tickerData = ticker.Price{
Last: resp[j].Last,
High: resp[j].High24h,
Low: resp[j].Low24h,
Bid: resp[j].BestBid,
Ask: resp[j].BestAsk,
Volume: resp[j].BaseVolume24h,
QuoteVolume: resp[j].QuoteVolume24h,
Open: resp[j].Open24h,
Pair: pairs[i],
LastUpdated: resp[j].Timestamp,
}
err = ticker.ProcessTicker(o.Name, &tickerData, assetType)
if err != nil {
log.Error(log.Ticker, err)
}
}
}
}
return ticker.GetTicker(o.GetName(), p, assetType)
}
// FetchTicker returns the ticker for a currency pair
func (o *OKCoin) FetchTicker(p currency.Pair, assetType asset.Item) (tickerData ticker.Price, err error) {
tickerData, err = ticker.GetTicker(o.GetName(), p, assetType)
if err != nil {
return o.UpdateTicker(p, assetType)
}
return
}

View File

@@ -11,6 +11,7 @@ import (
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/request"
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
"github.com/thrasher-corp/gocryptotrader/exchanges/websocket/wshandler"
log "github.com/thrasher-corp/gocryptotrader/logger"
)
@@ -56,17 +57,34 @@ func (o *OKEX) SetDefaults() {
asset.PerpetualSwap,
asset.Index,
},
UseGlobalFormat: true,
UseGlobalFormat: false,
}
// Same format used for perpetual swap and futures
fmt1 := currency.PairStore{
RequestFormat: &currency.PairFormat{
Uppercase: false,
Delimiter: "_",
Uppercase: true,
Delimiter: "-",
},
ConfigFormat: &currency.PairFormat{
Uppercase: true,
Delimiter: "_",
},
}
o.CurrencyPairs.Store(asset.PerpetualSwap, fmt1)
o.CurrencyPairs.Store(asset.Futures, fmt1)
fmt2 := currency.PairStore{
RequestFormat: &currency.PairFormat{
Uppercase: true,
Delimiter: "-",
},
ConfigFormat: &currency.PairFormat{
Uppercase: true,
Delimiter: "-",
},
}
o.CurrencyPairs.Store(asset.Spot, fmt2)
o.CurrencyPairs.Store(asset.Index, fmt2)
o.Features = exchange.Features{
Supports: exchange.FeaturesSupported{
@@ -74,6 +92,7 @@ func (o *OKEX) SetDefaults() {
Websocket: true,
RESTCapabilities: exchange.ProtocolFeatures{
AutoPairUpdates: true,
TickerBatching: true,
},
WithdrawPermissions: exchange.AutoWithdrawCrypto |
exchange.NoFiatWithdrawals,
@@ -121,6 +140,32 @@ func (o *OKEX) Run() {
if o.Verbose {
log.Debugf(log.ExchangeSys, "%s Websocket: %s. (url: %s).\n", o.GetName(), common.IsEnabled(o.Websocket.IsEnabled()), o.API.Endpoints.WebsocketURL)
}
if o.Config.CurrencyPairs.Pairs[asset.Spot].ConfigFormat == nil || o.Config.CurrencyPairs.Pairs[asset.Spot].RequestFormat == nil {
fmt := currency.PairStore{
RequestFormat: &currency.PairFormat{
Uppercase: true,
Delimiter: "-",
},
ConfigFormat: &currency.PairFormat{
Uppercase: true,
Delimiter: "-",
},
}
o.CurrencyPairs.Store(asset.Spot, fmt)
o.Config.CurrencyPairs.Store(asset.Spot, fmt)
}
if !common.StringDataContains(o.Config.CurrencyPairs.Pairs[asset.Spot].Enabled.Strings(), o.CurrencyPairs.Pairs[asset.Spot].RequestFormat.Delimiter) {
enabledPairs := currency.NewPairsFromStrings([]string{"EOS-USDT"})
log.Warnf(log.ExchangeSys,
"Enabled pairs for %v reset due to config upgrade, please enable the ones you would like again.", o.Name)
err := o.UpdatePairs(enabledPairs, asset.Spot, true, true)
if err != nil {
log.Errorf(log.ExchangeSys, "%s failed to update currencies.\n", o.GetName())
return
}
}
if !o.GetEnabledFeatures().AutoPairUpdates {
return
@@ -143,7 +188,7 @@ func (o *OKEX) FetchTradablePairs(i asset.Item) ([]string, error) {
}
for x := range prods {
pairs = append(pairs, prods[x].BaseCurrency+"_"+prods[x].QuoteCurrency)
pairs = append(pairs, fmt.Sprintf("%v%v%v", prods[x].BaseCurrency, o.GetPairFormat(i, false).Delimiter, prods[x].QuoteCurrency))
}
return pairs, nil
case asset.Futures:
@@ -154,7 +199,7 @@ func (o *OKEX) FetchTradablePairs(i asset.Item) ([]string, error) {
var pairs []string
for x := range prods {
pairs = append(pairs, prods[x].UnderlyingIndex+prods[x].QuoteCurrency+"_"+prods[x].Delivery)
pairs = append(pairs, fmt.Sprintf("%v%v%v", prods[x].UnderlyingIndex+prods[x].QuoteCurrency, o.GetPairFormat(i, false).Delimiter, prods[x].Delivery))
}
return pairs, nil
@@ -166,11 +211,11 @@ func (o *OKEX) FetchTradablePairs(i asset.Item) ([]string, error) {
var pairs []string
for x := range prods {
pairs = append(pairs, prods[x].UnderlyingIndex+"_"+prods[x].QuoteCurrency+"_SWAP")
pairs = append(pairs, fmt.Sprintf("%v%v%v%vSWAP", prods[x].UnderlyingIndex, o.GetPairFormat(i, false).Delimiter, prods[x].QuoteCurrency, o.GetPairFormat(i, false).Delimiter))
}
return pairs, nil
case asset.Index:
return []string{"BTC_USD"}, nil
return []string{fmt.Sprintf("BTC%vUSD", o.GetPairFormat(i, false).Delimiter)}, nil
}
return nil, fmt.Errorf("%s invalid asset type", o.Name)
@@ -193,3 +238,104 @@ func (o *OKEX) UpdateTradablePairs(forceUpdate bool) error {
}
return nil
}
// UpdateTicker updates and returns the ticker for a currency pair
func (o *OKEX) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Price, error) {
var tickerData ticker.Price
switch assetType {
case asset.Spot:
resp, err := o.GetSpotAllTokenPairsInformation()
if err != nil {
return tickerData, err
}
pairs := o.GetEnabledPairs(assetType)
for i := range pairs {
for j := range resp {
if !pairs[i].Equal(resp[j].InstrumentID) {
continue
}
tickerData = ticker.Price{
Last: resp[j].Last,
High: resp[j].High24h,
Low: resp[j].Low24h,
Bid: resp[j].BestBid,
Ask: resp[j].BestAsk,
Volume: resp[j].BaseVolume24h,
QuoteVolume: resp[j].QuoteVolume24h,
Open: resp[j].Open24h,
Pair: pairs[i],
LastUpdated: resp[j].Timestamp,
}
err = ticker.ProcessTicker(o.Name, &tickerData, assetType)
if err != nil {
log.Error(log.Ticker, err)
}
}
}
case asset.PerpetualSwap:
resp, err := o.GetAllSwapTokensInformation()
if err != nil {
return tickerData, err
}
pairs := o.GetEnabledPairs(assetType)
for i := range pairs {
for j := range resp {
if !pairs[i].Equal(resp[j].InstrumentID) {
continue
}
tickerData = ticker.Price{
Last: resp[j].Last,
High: resp[j].High24H,
Low: resp[j].Low24H,
Bid: resp[j].BestBid,
Ask: resp[j].BestAsk,
Volume: resp[j].Volume24H,
Pair: resp[j].InstrumentID,
LastUpdated: resp[j].Timestamp,
}
err = ticker.ProcessTicker(o.Name, &tickerData, assetType)
if err != nil {
log.Error(log.Ticker, err)
}
}
}
case asset.Futures:
resp, err := o.GetAllFuturesTokenInfo()
if err != nil {
return tickerData, err
}
pairs := o.GetEnabledPairs(assetType)
for i := range pairs {
for j := range resp {
if !pairs[i].Equal(resp[j].InstrumentID) {
continue
}
tickerData = ticker.Price{
Last: resp[j].Last,
High: resp[j].High24h,
Low: resp[j].Low24h,
Bid: resp[j].BestBid,
Ask: resp[j].BestAsk,
Volume: resp[j].Volume24h,
Pair: resp[j].InstrumentID,
LastUpdated: resp[j].Timestamp,
}
err = ticker.ProcessTicker(o.Name, &tickerData, assetType)
if err != nil {
log.Error(log.Ticker, err)
}
}
}
}
return ticker.GetTicker(o.GetName(), p, assetType)
}
// FetchTicker returns the ticker for a currency pair
func (o *OKEX) FetchTicker(p currency.Pair, assetType asset.Item) (tickerData ticker.Price, err error) {
tickerData, err = ticker.GetTicker(o.GetName(), p, assetType)
if err != nil {
return o.UpdateTicker(p, assetType)
}
return
}

View File

@@ -2,6 +2,8 @@ package okgroup
import (
"time"
"github.com/thrasher-corp/gocryptotrader/currency"
)
// GetAccountCurrenciesResponse response data for GetAccountCurrencies
@@ -288,16 +290,16 @@ type GetSpotOrderBookResponse struct {
// GetSpotTokenPairsInformationResponse response data for GetSpotTokenPairsInformation
type GetSpotTokenPairsInformationResponse struct {
BaseVolume24h float64 `json:"base_volume_24h,string"` // 24 trading volume of the base currency
BestAsk float64 `json:"best_ask,string"` // best ask price
BestBid float64 `json:"best_bid,string"` // best bid price
High24h float64 `json:"high_24h,string"` // 24 hour high
InstrumentID string `json:"instrument_id"` // trading pair
Last float64 `json:"last,string"` // last traded price
Low24h float64 `json:"low_24h,string"` // 24 hour low
Open24h float64 `json:"open_24h,string"` // 24 hour open
QuoteVolume24h float64 `json:"quote_volume_24h,string"` // 24 trading volume of the quote currency
Timestamp time.Time `json:"timestamp"`
BaseVolume24h float64 `json:"base_volume_24h,string"` // 24 trading volume of the base currency
BestAsk float64 `json:"best_ask,string"` // best ask price
BestBid float64 `json:"best_bid,string"` // best bid price
High24h float64 `json:"high_24h,string"` // 24 hour high
InstrumentID currency.Pair `json:"instrument_id"` // trading pair
Last float64 `json:"last,string"` // last traded price
Low24h float64 `json:"low_24h,string"` // 24 hour low
Open24h float64 `json:"open_24h,string"` // 24 hour open
QuoteVolume24h float64 `json:"quote_volume_24h,string"` // 24 trading volume of the quote currency
Timestamp time.Time `json:"timestamp"`
}
// GetSpotFilledOrdersInformationRequest request data for GetSpotFilledOrdersInformation
@@ -699,14 +701,14 @@ type GetFuturesOrderBookResponse struct {
// GetFuturesTokenInfoResponse response data for GetFuturesOrderBook
type GetFuturesTokenInfoResponse struct {
BestAsk float64 `json:"best_ask,string"`
BestBid float64 `json:"best_bid,string"`
High24h float64 `json:"high_24h,string"`
InstrumentID string `json:"instrument_id"`
Last float64 `json:"last,string"`
Low24h float64 `json:"low_24h,string"`
Timestamp time.Time `json:"timestamp"`
Volume24h int64 `json:"volume_24h,string"`
BestAsk float64 `json:"best_ask,string"`
BestBid float64 `json:"best_bid,string"`
High24h float64 `json:"high_24h,string"`
InstrumentID currency.Pair `json:"instrument_id"`
Last float64 `json:"last,string"`
Low24h float64 `json:"low_24h,string"`
Timestamp time.Time `json:"timestamp"`
Volume24h float64 `json:"volume_24h,string"`
}
// GetFuturesFilledOrderRequest request data for GetFuturesFilledOrder
@@ -1057,14 +1059,14 @@ type GetSwapOrderBookResponse struct {
// GetAllSwapTokensInformationResponse response data for GetAllSwapTokensInformation
type GetAllSwapTokensInformationResponse struct {
InstrumentID string `json:"instrument_id"`
Last float64 `json:"last,string"`
High24H float64 `json:"high_24h,string"`
Low24H float64 `json:"low_24h,string"`
BestBid float64 `json:"best_bid,string"`
BestAsk float64 `json:"best_ask,string"`
Volume24H float64 `json:"volume_24h,string"`
Timestamp time.Time `json:"timestamp"`
InstrumentID currency.Pair `json:"instrument_id"`
Last float64 `json:"last,string"`
High24H float64 `json:"high_24h,string"`
Low24H float64 `json:"low_24h,string"`
BestBid float64 `json:"best_bid,string"`
BestAsk float64 `json:"best_ask,string"`
Volume24H float64 `json:"volume_24h,string"`
Timestamp time.Time `json:"timestamp"`
}
// GetSwapFilledOrdersDataRequest request data for GetSwapFilledOrdersData
@@ -1340,12 +1342,14 @@ type WebsocketDataWrapper struct {
// WebsocketTickerData contains formatted data for ticker related websocket responses
type WebsocketTickerData struct {
High24H float64 `json:"high_24h,string,omitempty"`
Last float64 `json:"last,string,omitempty"`
BestBid float64 `json:"best_bid,string,omitempty"`
BestAsk float64 `json:"best_ask,string,omitempty"`
Low24H float64 `json:"low_24h,string,omitempty"`
Volume24H float64 `json:"volume_24h,string,omitempty"`
BaseVolume24h float64 `json:"base_volume_24h,string,omitempty"`
BestAsk float64 `json:"best_ask,string,omitempty"`
BestBid float64 `json:"best_bid,string,omitempty"`
High24h float64 `json:"high_24h,string,omitempty"`
Last float64 `json:"last,string,omitempty"`
Low24h float64 `json:"low_24h,string,omitempty"`
Open24h float64 `json:"open_24h,string,omitempty"`
QuoteVolume24h float64 `json:"quote_volume_24h,string,omitempty"`
}
// WebsocketTradeResponse contains formatted data for trade related websocket responses

View File

@@ -193,7 +193,7 @@ func (o *OKGroup) wsPingHandler(wg *sync.WaitGroup) {
return
case <-ticker.C:
err := o.WebsocketConn.SendMessage("ping")
err := o.WebsocketConn.Connection.WriteMessage(websocket.TextMessage, []byte("ping"))
if o.Verbose {
log.Debugf(log.ExchangeSys, "%v sending ping", o.GetName())
}
@@ -361,13 +361,19 @@ func (o *OKGroup) wsProcessTickers(response *WebsocketDataResponse) {
for i := range response.Data {
instrument := currency.NewPairDelimiter(response.Data[i].InstrumentID, "-")
o.Websocket.DataHandler <- wshandler.TickerData{
Timestamp: response.Data[i].Timestamp,
Exchange: o.GetName(),
AssetType: o.GetAssetTypeFromTableName(response.Table),
HighPrice: response.Data[i].High24H,
LowPrice: response.Data[i].Low24H,
ClosePrice: response.Data[i].Last,
Pair: instrument,
Exchange: o.Name,
Open: response.Data[i].Open24h,
Close: response.Data[i].Last,
Volume: response.Data[i].BaseVolume24h,
QuoteVolume: response.Data[i].QuoteVolume24h,
High: response.Data[i].High24h,
Low: response.Data[i].Low24h,
Bid: response.Data[i].BestBid,
Ask: response.Data[i].BestAsk,
Last: response.Data[i].Last,
Timestamp: response.Data[i].Timestamp,
AssetType: o.GetAssetTypeFromTableName(response.Table),
Pair: instrument,
}
}
}

View File

@@ -11,7 +11,6 @@ import (
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
"github.com/thrasher-corp/gocryptotrader/exchanges/websocket/wshandler"
log "github.com/thrasher-corp/gocryptotrader/logger"
)
@@ -65,36 +64,6 @@ func (o *OKGroup) Setup(exch *config.ExchangeConfig) error {
return nil
}
// UpdateTicker updates and returns the ticker for a currency pair
func (o *OKGroup) UpdateTicker(p currency.Pair, assetType asset.Item) (tickerData ticker.Price, err error) {
resp, err := o.GetSpotAllTokenPairsInformationForCurrency(o.FormatExchangeCurrency(p, assetType).String())
if err != nil {
return
}
tickerData = ticker.Price{
Ask: resp.BestAsk,
Bid: resp.BestBid,
High: resp.High24h,
Last: resp.Last,
LastUpdated: resp.Timestamp,
Low: resp.Low24h,
Pair: o.FormatExchangeCurrency(p, assetType),
Volume: resp.BaseVolume24h,
}
err = ticker.ProcessTicker(o.Name, &tickerData, assetType)
return
}
// FetchTicker returns the ticker for a currency pair
func (o *OKGroup) FetchTicker(p currency.Pair, assetType asset.Item) (tickerData ticker.Price, err error) {
tickerData, err = ticker.GetTicker(o.GetName(), p, assetType)
if err != nil {
return o.UpdateTicker(p, assetType)
}
return
}
// FetchOrderbook returns orderbook base on the currency pair
func (o *OKGroup) FetchOrderbook(p currency.Pair, assetType asset.Item) (resp orderbook.Base, err error) {
ob, err := orderbook.Get(o.GetName(), p, assetType)
@@ -339,7 +308,7 @@ func (o *OKGroup) GetOrderInfo(orderID string) (resp exchange.OrderDetail, err e
// GetDepositAddress returns a deposit address for a specified currency
func (o *OKGroup) GetDepositAddress(p currency.Code, accountID string) (_ string, err error) {
wallet, err := o.GetAccountDepositAddressForCurrency(p.Lower().String())
if err != nil {
if err != nil || len(wallet) == 0 {
return
}
return wallet[0].Address, nil

View File

@@ -210,23 +210,22 @@ func (p *Poloniex) wsHandleTickerData(data []interface{}) {
t.PercentageChange, _ = strconv.ParseFloat(tickerData[4].(string), 64)
t.BaseCurrencyVolume24H, _ = strconv.ParseFloat(tickerData[5].(string), 64)
t.QuoteCurrencyVolume24H, _ = strconv.ParseFloat(tickerData[6].(string), 64)
isFrozen := false
if tickerData[7].(float64) == 1 {
isFrozen = true
}
t.IsFrozen = isFrozen
t.IsFrozen = tickerData[7].(float64) == 1
t.HighestTradeIn24H, _ = strconv.ParseFloat(tickerData[8].(string), 64)
t.LowestTradePrice24H, _ = strconv.ParseFloat(tickerData[9].(string), 64)
p.Websocket.DataHandler <- wshandler.TickerData{
Timestamp: time.Now(),
Pair: currency.NewPairDelimiter(currencyPair, "_"),
Exchange: p.GetName(),
AssetType: asset.Spot,
ClosePrice: t.LastPrice,
LowPrice: t.LowestAsk,
HighPrice: t.HighestBid,
Quantity: t.QuoteCurrencyVolume24H,
Exchange: p.Name,
Volume: t.BaseCurrencyVolume24H,
QuoteVolume: t.QuoteCurrencyVolume24H,
High: t.HighestBid,
Low: t.LowestAsk,
Bid: t.HighestBid,
Ask: t.LowestAsk,
Last: t.LastPrice,
Timestamp: time.Now(),
AssetType: asset.Spot,
Pair: currency.NewPairDelimiter(currencyPair, "_"),
}
}
@@ -362,7 +361,6 @@ func (p *Poloniex) WsProcessOrderbookUpdate(sequenceNumber int64, target []inter
// GenerateDefaultSubscriptions Adds default subscriptions to websocket to be handled by ManageSubscriptions()
func (p *Poloniex) GenerateDefaultSubscriptions() {
var subscriptions []wshandler.WebsocketChannelSubscription
// Tickerdata is its own channel
subscriptions = append(subscriptions, wshandler.WebsocketChannelSubscription{
Channel: fmt.Sprintf("%v", wsTickerDataID),
})

View File

@@ -215,6 +215,9 @@ func (p *Poloniex) UpdateTicker(currencyPair currency.Pair, assetType asset.Item
for _, x := range p.GetEnabledPairs(assetType) {
var tp ticker.Price
curr := p.FormatExchangeCurrency(x, assetType).String()
if _, ok := tick[curr]; !ok {
continue
}
tp.Pair = x
tp.Ask = tick[curr].LowestAsk
tp.Bid = tick[curr].HighestBid
@@ -222,10 +225,11 @@ func (p *Poloniex) UpdateTicker(currencyPair currency.Pair, assetType asset.Item
tp.Last = tick[curr].Last
tp.Low = tick[curr].Low24Hr
tp.Volume = tick[curr].BaseVolume
tp.QuoteVolume = tick[curr].QuoteVolume
err = ticker.ProcessTicker(p.GetName(), &tp, assetType)
if err != nil {
return tickerPrice, err
log.Error(log.Ticker, err)
}
}
return ticker.GetTicker(p.Name, currencyPair, assetType)

View File

@@ -2,6 +2,7 @@ package ticker
import (
"errors"
"fmt"
"strconv"
"strings"
"sync"
@@ -28,14 +29,17 @@ var (
// Price struct stores the currency pair and pricing information
type Price struct {
Pair currency.Pair `json:"Pair"`
Last float64 `json:"Last"`
High float64 `json:"High"`
Low float64 `json:"Low"`
Bid float64 `json:"Bid"`
Ask float64 `json:"Ask"`
Volume float64 `json:"Volume"`
QuoteVolume float64 `json:"QuoteVolume"`
PriceATH float64 `json:"PriceATH"`
Open float64 `json:"Open"`
Close float64 `json:"Close"`
Pair currency.Pair `json:"Pair"`
LastUpdated time.Time
}
@@ -151,11 +155,11 @@ func CreateNewTicker(exchangeName string, tickerNew *Price, tickerType asset.Ite
// list
func ProcessTicker(exchangeName string, tickerNew *Price, assetType asset.Item) error {
if tickerNew.Pair.IsEmpty() {
return errors.New(errPairNotSet)
return fmt.Errorf("%v %v", exchangeName, errPairNotSet)
}
if assetType == "" {
return errors.New(errAssetTypeNotSet)
return fmt.Errorf("%v %v %v", exchangeName, tickerNew.Pair.String(), errAssetTypeNotSet)
}
if tickerNew.LastUpdated.IsZero() {
@@ -178,6 +182,7 @@ func ProcessTicker(exchangeName string, tickerNew *Price, assetType asset.Item)
}
m.Lock()
a := make(map[string]map[string]Price)
b := make(map[string]Price)
b[assetType.String()] = *tickerNew

View File

@@ -103,7 +103,9 @@ func (w *Websocket) Connect() error {
if !w.connectionMonitorRunning {
go w.connectionMonitor()
}
go w.manageSubscriptions()
if w.SupportsFunctionality(WebsocketSubscribeSupported) || w.SupportsFunctionality(WebsocketUnsubscribeSupported) {
go w.manageSubscriptions()
}
return nil
}

View File

@@ -144,15 +144,20 @@ type TradeData struct {
// TickerData defines ticker feed
type TickerData struct {
Timestamp time.Time
Pair currency.Pair
AssetType asset.Item
Exchange string
ClosePrice float64
Quantity float64
OpenPrice float64
HighPrice float64
LowPrice float64
Exchange string
Open float64
Close float64
Volume float64
QuoteVolume float64
High float64
Low float64
Bid float64
Ask float64
Last float64
PriceATH float64
Timestamp time.Time
AssetType asset.Item
Pair currency.Pair
}
// KlineData defines kline feed

View File

@@ -170,19 +170,23 @@ func (y *Yobit) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Pric
}
for _, x := range y.GetEnabledPairs(assetType) {
currency := y.FormatExchangeCurrency(x, assetType).Lower().String()
curr := y.FormatExchangeCurrency(x, assetType).Lower().String()
if _, ok := result[curr]; !ok {
continue
}
var tickerPrice ticker.Price
tickerPrice.Pair = x
tickerPrice.Last = result[currency].Last
tickerPrice.Ask = result[currency].Sell
tickerPrice.Bid = result[currency].Buy
tickerPrice.Last = result[currency].Last
tickerPrice.Low = result[currency].Low
tickerPrice.Volume = result[currency].VolumeCurrent
tickerPrice.Last = result[curr].Last
tickerPrice.Ask = result[curr].Sell
tickerPrice.Bid = result[curr].Buy
tickerPrice.Last = result[curr].Last
tickerPrice.Low = result[curr].Low
tickerPrice.QuoteVolume = result[curr].VolumeCurrent
tickerPrice.Volume = result[curr].Vol
err = ticker.ProcessTicker(y.Name, &tickerPrice, assetType)
if err != nil {
return tickerPrice, err
log.Error(log.Ticker, err)
}
}
return ticker.GetTicker(y.Name, p, assetType)

View File

@@ -72,12 +72,12 @@ type TickerResponse struct {
// TickerChildResponse holds the ticker child response data
type TickerChildResponse struct {
Vol float64 `json:"vol,string"` // 成交量(最近的24小时)
Last float64 `json:"last,string"` // 最新成交价
Sell float64 `json:"sell,string"` // 卖一价
Buy float64 `json:"buy,string"` // 买一价
High float64 `json:"high,string"` // 最高价
Low float64 `json:"low,string"` // 最低价
Volume float64 `json:"vol,string"` // 成交量(最近的24小时)
Last float64 `json:"last,string"` // 最新成交价
Sell float64 `json:"sell,string"` // 卖一价
Buy float64 `json:"buy,string"` // 买一价
High float64 `json:"high,string"` // 最高价
Low float64 `json:"low,string"` // 最低价
}
// SpotNewOrderRequestParamsType ZB 交易类型

View File

@@ -96,13 +96,17 @@ func (z *ZB) WsHandleData() {
}
z.Websocket.DataHandler <- wshandler.TickerData{
Timestamp: time.Unix(0, ticker.Date),
Pair: currency.NewPairFromString(cPair[0]),
AssetType: asset.Spot,
Exchange: z.GetName(),
ClosePrice: ticker.Data.Last,
HighPrice: ticker.Data.High,
LowPrice: ticker.Data.Low,
Exchange: z.Name,
Close: ticker.Data.Last,
Volume: ticker.Data.Volume24Hr,
High: ticker.Data.High,
Low: ticker.Data.Low,
Last: ticker.Data.Last,
Bid: ticker.Data.Buy,
Ask: ticker.Data.Sell,
Timestamp: time.Unix(0, ticker.Date),
AssetType: asset.Spot,
Pair: currency.NewPairFromString(cPair[0]),
}
case strings.Contains(result.Channel, "depth"):

View File

@@ -204,21 +204,23 @@ func (z *ZB) UpdateTicker(p currency.Pair, assetType asset.Item) (ticker.Price,
}
for _, x := range z.GetEnabledPairs(assetType) {
currencySplit := strings.Split(z.FormatExchangeCurrency(x, assetType).String(), "_")
currency := currencySplit[0] + currencySplit[1]
currencySplit := strings.Split(z.FormatExchangeCurrency(x, assetType).String(), z.GetPairFormat(assetType, false).Delimiter)
curr := currencySplit[0] + currencySplit[1]
if _, ok := result[curr]; !ok {
continue
}
var tp ticker.Price
tp.Pair = x
tp.High = result[currency].High
tp.Last = result[currency].Last
tp.Ask = result[currency].Sell
tp.Bid = result[currency].Buy
tp.Last = result[currency].Last
tp.Low = result[currency].Low
tp.Volume = result[currency].Vol
tp.High = result[curr].High
tp.Last = result[curr].Last
tp.Ask = result[curr].Sell
tp.Bid = result[curr].Buy
tp.Low = result[curr].Low
tp.Volume = result[curr].Volume
err = ticker.ProcessTicker(z.Name, &tp, assetType)
if err != nil {
return tickerPrice, err
log.Error(log.Ticker, err)
}
}

View File

@@ -22,6 +22,7 @@ func (l *Logger) newLogEvent(data, header string, w io.Writer) error {
if w == nil {
return errors.New("io.Writer not set")
}
e := eventPool.Get().(*LogEvent)
e.output = w
e.data = append(e.data, []byte(header)...)
@@ -34,11 +35,12 @@ func (l *Logger) newLogEvent(data, header string, w io.Writer) error {
if data == "" || data[len(data)-1] != '\n' {
e.data = append(e.data, '\n')
}
e.output.Write(e.data)
_, err := e.output.Write(e.data)
e.data = e.data[:0]
eventPool.Put(e)
return nil
return err
}
// CloseLogger is called on shutdown of application
@@ -58,6 +60,7 @@ func validSubLogger(s string) (bool, *subLogger) {
return false, nil
}
// Level retries the current sublogger levels
func Level(s string) (*Levels, error) {
found, logger := validSubLogger(s)
if !found {
@@ -67,6 +70,7 @@ func Level(s string) (*Levels, error) {
return &logger.Levels, nil
}
// SetLevel sets sublogger levels
func SetLevel(s, level string) (*Levels, error) {
found, logger := validSubLogger(s)
if !found {

View File

@@ -11,7 +11,7 @@ func (mw *multiWriter) Add(writer io.Writer) {
mw.mu.Unlock()
}
// Remove removes exisiting writer from multiwriter slice
// Remove removes existing writer from multiwriter slice
func (mw *multiWriter) Remove(writer io.Writer) {
mw.mu.Lock()
@@ -37,8 +37,10 @@ func (mw *multiWriter) Write(p []byte) (n int, err error) {
n int
err error
}
mw.mu.RLock()
defer mw.mu.RUnlock()
results := make(chan data)
results := make(chan data, len(mw.writers))
for _, wr := range mw.writers {
go func(w io.Writer, p []byte, ch chan data) {
@@ -51,10 +53,7 @@ func (mw *multiWriter) Write(p []byte) (n int, err error) {
ch <- data{n, io.ErrShortWrite}
return
}
select {
case ch <- data{n, nil}:
default:
}
ch <- data{n, nil}
}(wr, p, results)
}

View File

@@ -72,13 +72,12 @@ func (r *Rotate) openOrCreateFile(n int64) error {
func (r *Rotate) openNew() error {
name := filepath.Join(LogPath, r.FileName)
t := time.Now()
timestamp := t.Format("2006-01-02T15-04-05")
newName := filepath.Join(LogPath, timestamp+"-"+r.FileName)
_, err := os.Stat(name)
if err == nil {
timestamp := time.Now().Format("2006-01-02T15-04-05")
newName := filepath.Join(LogPath, timestamp+"-"+r.FileName)
err = os.Rename(name, newName)
if err != nil {
return fmt.Errorf("can't rename log file: %s", err)
@@ -105,6 +104,7 @@ func (r *Rotate) close() (err error) {
return err
}
// Close handler for open file
func (r *Rotate) Close() error {
r.mu.Lock()
defer r.mu.Unlock()

View File

@@ -27,7 +27,6 @@ func getWriters(s *SubLoggerConfig) io.Writer {
m.Add(ioutil.Discard)
}
}
return m
}

View File

@@ -51,6 +51,7 @@ type Logger struct {
Spacer string
}
// Levels flags for each sub logger type
type Levels struct {
Info, Debug, Warn, Error bool
}
@@ -61,6 +62,7 @@ type subLogger struct {
output io.Writer
}
// LogEvent holds the data sent to the log and which multiwriter to send to
type LogEvent struct {
data []byte
output io.Writer
@@ -68,14 +70,17 @@ type LogEvent struct {
type multiWriter struct {
writers []io.Writer
mu sync.Mutex
mu sync.RWMutex
}
var (
logger = &Logger{}
logger = &Logger{}
// FileLoggingConfiguredCorrectly flag set during config check if file logging meets requirements
FileLoggingConfiguredCorrectly bool
GlobalLogConfig = &Config{} // GlobalLogConfig hold global configuration options for logger
GlobalLogFile = &Rotate{}
// GlobalLogConfig holds global configuration options for logger
GlobalLogConfig = &Config{}
// GlobalLogFile hold global configuration options for file logger
GlobalLogFile = &Rotate{}
eventPool = &sync.Pool{
New: func() interface{} {
@@ -85,5 +90,6 @@ var (
},
}
// LogPath system path to store log files in
LogPath string
)

View File

@@ -2,6 +2,7 @@ package logger
import (
"fmt"
"log"
)
// Info takes a pointer subLogger struct and string sends to newLogEvent
@@ -14,7 +15,7 @@ func Info(sl *subLogger, data string) {
return
}
logger.newLogEvent(data, logger.InfoHeader, sl.output)
displayError(logger.newLogEvent(data, logger.InfoHeader, sl.output))
}
// Infoln takes a pointer subLogger struct and interface sends to newLogEvent
@@ -27,7 +28,7 @@ func Infoln(sl *subLogger, v ...interface{}) {
return
}
logger.newLogEvent(fmt.Sprintln(v...), logger.InfoHeader, sl.output)
displayError(logger.newLogEvent(fmt.Sprintln(v...), logger.InfoHeader, sl.output))
}
// Infof takes a pointer subLogger struct, string & interface formats and sends to Info()
@@ -53,7 +54,7 @@ func Debug(sl *subLogger, data string) {
return
}
logger.newLogEvent(data, logger.DebugHeader, sl.output)
displayError(logger.newLogEvent(data, logger.DebugHeader, sl.output))
}
// Debugln takes a pointer subLogger struct, string and interface sends to newLogEvent
@@ -66,7 +67,7 @@ func Debugln(sl *subLogger, v ...interface{}) {
return
}
logger.newLogEvent(fmt.Sprintln(v...), logger.DebugHeader, sl.output)
displayError(logger.newLogEvent(fmt.Sprintln(v...), logger.DebugHeader, sl.output))
}
// Debugf takes a pointer subLogger struct, string & interface formats and sends to Info()
@@ -92,7 +93,7 @@ func Warn(sl *subLogger, data string) {
return
}
logger.newLogEvent(data, logger.WarnHeader, sl.output)
displayError(logger.newLogEvent(data, logger.WarnHeader, sl.output))
}
// Warnln takes a pointer subLogger struct & interface formats and sends to newLogEvent()
@@ -105,7 +106,7 @@ func Warnln(sl *subLogger, v ...interface{}) {
return
}
logger.newLogEvent(fmt.Sprintln(v...), logger.WarnHeader, sl.output)
displayError(logger.newLogEvent(fmt.Sprintln(v...), logger.WarnHeader, sl.output))
}
// Warnf takes a pointer subLogger struct, string & interface formats and sends to Warn()
@@ -131,7 +132,7 @@ func Error(sl *subLogger, data ...interface{}) {
return
}
logger.newLogEvent(fmt.Sprint(data...), logger.ErrorHeader, sl.output)
displayError(logger.newLogEvent(fmt.Sprint(data...), logger.ErrorHeader, sl.output))
}
// Errorln takes a pointer subLogger struct, string & interface formats and sends to newLogEvent()
@@ -144,7 +145,7 @@ func Errorln(sl *subLogger, v ...interface{}) {
return
}
logger.newLogEvent(fmt.Sprintln(v...), logger.ErrorHeader, sl.output)
displayError(logger.newLogEvent(fmt.Sprintln(v...), logger.ErrorHeader, sl.output))
}
// Errorf takes a pointer subLogger struct, string & interface formats and sends to Debug()
@@ -159,3 +160,9 @@ func Errorf(sl *subLogger, data string, v ...interface{}) {
Error(sl, fmt.Sprintf(data, v...))
}
func displayError(err error) {
if err != nil {
log.Printf("Logger write error: %v\n", err)
}
}

View File

@@ -1,5 +1,6 @@
package logger
//nolint
var (
subLoggers = map[string]*subLogger{}

View File

@@ -2729,6 +2729,64 @@
}
}
]
},
"/v2/ticker/BTCUSD": {
"GET": [
{
"data": {
"ask": "9663.28",
"bid": "9662.94",
"changes": [
"9719",
"9730.13",
"9718.58",
"9672.54",
"9668.57",
"9701.67",
"10191.27",
"10225.8",
"10238.78",
"10210.5",
"10171.2",
"10156.31",
"10138.69",
"10121.71",
"10147.31",
"10120.74",
"10149.82",
"10185.68",
"10128.28",
"10070.56",
"10082.86",
"10114",
"10089.25",
"10142.29"
],
"close": "9662.94",
"high": "11000",
"low": "9210",
"open": "10148.67",
"symbol": "BTCUSD"
},
"queryString": "",
"bodyParams": "",
"headers": {}
}
]
},
"/v2/ticker/bla": {
"GET": [
{
"data": {
"message": "Supplied value 'bla' is not a valid symbol. Please correct your API request to use one of the supported symbols: [zecbch, bchbtc, zecusd, ethusd, zecbtc, bcheth, zecltc, ltcbch, bchusd, ethbtc, ltcbtc, ltceth, zeceth, ltcusd, btcusd]",
"reason": "Bad Request",
"result": "error"
},
"queryString": "",
"bodyParams": "",
"headers": {}
}
]
}
}
}