diff --git a/API.go b/API.go index 1e41f6d6..80009eba 100644 --- a/API.go +++ b/API.go @@ -3,8 +3,8 @@ package goex // api interface type API interface { - LimitBuy(amount, price string, currency CurrencyPair) (*Order, error) - LimitSell(amount, price string, currency CurrencyPair) (*Order, error) + LimitBuy(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) + LimitSell(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) MarketBuy(amount, price string, currency CurrencyPair) (*Order, error) MarketSell(amount, price string, currency CurrencyPair) (*Order, error) CancelOrder(orderId string, currency CurrencyPair) (bool, error) @@ -15,7 +15,7 @@ type API interface { GetTicker(currency CurrencyPair) (*Ticker, error) GetDepth(size int, currency CurrencyPair) (*Depth, error) - GetKlineRecords(currency CurrencyPair, period , size, since int) ([]Kline, error) + GetKlineRecords(currency CurrencyPair, period, size, since int) ([]Kline, error) //非个人,整个交易所的交易记录 GetTrades(currencyPair CurrencyPair, since int64) ([]Trade, error) diff --git a/Const.go b/Const.go index 9d197b2a..1d137d4e 100644 --- a/Const.go +++ b/Const.go @@ -168,3 +168,24 @@ const ( TIPS //余币宝 SWAP //永续合约 ) + +type LimitOrderOptionalParameter int + +func (opt LimitOrderOptionalParameter) String() string { + switch opt { + case PostOnly: + return "post_only" + case Fok: + return "fok" + case Ioc: + return "ioc" + default: + return "error-order-optional-parameter" + } +} + +const ( + PostOnly LimitOrderOptionalParameter = iota + 1 + Ioc + Fok +) \ No newline at end of file diff --git a/FutureRestAPI.go b/FutureRestAPI.go index a80e538b..befa94dd 100644 --- a/FutureRestAPI.go +++ b/FutureRestAPI.go @@ -49,9 +49,12 @@ type FutureRestAPI interface { * @param openType 1:开多 2:开空 3:平多 4:平空 * @param matchPrice 是否为对手价 0:不是 1:是 ,当取值为1时,price无效 */ - PlaceFutureOrder(currencyPair CurrencyPair, contractType, price, amount string, openType, matchPrice, leverRate int) (string, error) + PlaceFutureOrder(currencyPair CurrencyPair, contractType, price, amount string, openType, matchPrice int, leverRate float64) (string, error) - LimitFuturesOrder(currencyPair CurrencyPair, contractType, price, amount string, openType int) (*FutureOrder, error) + LimitFuturesOrder(currencyPair CurrencyPair, contractType, price, amount string, openType int, opt ...LimitOrderOptionalParameter) (*FutureOrder, error) + + //对手价下单 + MarketFuturesOrder(currencyPair CurrencyPair, contractType, amount string, openType int) (*FutureOrder, error) /** * 取消订单 @@ -108,10 +111,10 @@ type FutureRestAPI interface { /** * 获取K线数据 */ - GetKlineRecords(contract_type string, currency CurrencyPair, period, size, since int) ([]FutureKline, error) + GetKlineRecords(contractType string, currency CurrencyPair, period, size, since int) ([]FutureKline, error) /** * 获取Trade数据 */ - GetTrades(contract_type string, currencyPair CurrencyPair, since int64) ([]Trade, error) + GetTrades(contractType string, currencyPair CurrencyPair, since int64) ([]Trade, error) } diff --git a/Models.go b/Models.go index 87fad236..99801962 100644 --- a/Models.go +++ b/Models.go @@ -119,7 +119,7 @@ type APIConfig struct { ApiPassphrase string //for okex.com v3 api ClientId string //for bitstamp.net , huobi.pro - Lever int //杠杆倍数 , for future + Lever float64 //杠杆倍数 , for future } type Kline struct { @@ -163,10 +163,14 @@ type FutureOrder struct { Currency CurrencyPair OrderType int //ORDINARY=0 POST_ONLY=1 FOK= 2 IOC= 3 OType int //1:开多 2:开空 3:平多 4: 平空 - LeverRate int //倍数 + LeverRate float64 //倍数 Fee float64 //手续费 ContractName string FinishedTime int64 // finished timestamp + + //策略委托单 + TriggerPrice float64 + AlgoType int //1:限价 2:市场价;触发价格类型,默认是限价;为市场价时,委托价格不必填; } type FuturePosition struct { @@ -176,7 +180,7 @@ type FuturePosition struct { BuyPriceCost float64 BuyProfitReal float64 CreateDate int64 - LeverRate int + LeverRate float64 SellAmount float64 SellAvailable float64 SellPriceAvg float64 @@ -186,6 +190,8 @@ type FuturePosition struct { ContractType string ContractId int64 ForceLiquPrice float64 //预估爆仓价 + ShortPnlRatio float64 //空仓收益率 + LongPnlRatio float64 //多仓收益率 } type HistoricalFunding struct { @@ -222,7 +228,6 @@ type RepaymentParameter struct { BorrowId string } - type TransferParameter struct { Currency string `json:"currency"` From int `json:"from"` @@ -242,7 +247,6 @@ type WithdrawParameter struct { Fee string `json:"fee"` } - type DepositWithdrawHistory struct { WithdrawalId string `json:"withdrawal_id,omitempty"` Currency string `json:"currency"` diff --git a/README.md b/README.md index e46be10d..8d62b567 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@
goex - +
### goex目标 @@ -9,6 +9,10 @@ goex项目是为了统一并标准化各个数字资产交易平台的接口而 [English](https://github.com/nntaoli-project/goex/blob/dev/README_en.md) +### wiki文档 + +[文档](https://github.com/nntaoli-project/goex/wiki) + ### goex已支持交易所 `23+` | 交易所 | 行情接口 | 交易接口 | 版本号 | diff --git a/allcoin/allcoin.go b/allcoin/allcoin.go index 759640c0..b6440a7a 100755 --- a/allcoin/allcoin.go +++ b/allcoin/allcoin.go @@ -271,11 +271,11 @@ func (ac *Allcoin) GetAccount() (*Account, error) { return &acc, nil } -func (ac *Allcoin) LimitBuy(amount, price string, currencyPair CurrencyPair) (*Order, error) { +func (ac *Allcoin) LimitBuy(amount, price string, currencyPair CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return ac.placeOrder(amount, price, currencyPair, "LIMIT", "buy") } -func (ac *Allcoin) LimitSell(amount, price string, currencyPair CurrencyPair) (*Order, error) { +func (ac *Allcoin) LimitSell(amount, price string, currencyPair CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return ac.placeOrder(amount, price, currencyPair, "LIMIT", "sale") } diff --git a/atop/atop.go b/atop/atop.go index 00331e86..2c6c0c38 100644 --- a/atop/atop.go +++ b/atop/atop.go @@ -306,12 +306,12 @@ func (at *Atop) GetAccount() (*Account, error) { } //hao -func (at *Atop) LimitBuy(amount, price string, currencyPair CurrencyPair) (*Order, error) { +func (at *Atop) LimitBuy(amount, price string, currencyPair CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return at.plateOrder(amount, price, currencyPair, "limit", "buy") } //hao -func (at *Atop) LimitSell(amount, price string, currencyPair CurrencyPair) (*Order, error) { +func (at *Atop) LimitSell(amount, price string, currencyPair CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return at.plateOrder(amount, price, currencyPair, "limit", "sale") } diff --git a/bigone/Bigone.go b/bigone/Bigone.go index d84412ee..e0ca9920 100644 --- a/bigone/Bigone.go +++ b/bigone/Bigone.go @@ -167,11 +167,11 @@ func (bo *Bigone) placeOrder(amount, price string, pair goex.CurrencyPair, order OrderTime: int(time.Now().Unix())}, nil } -func (bo *Bigone) LimitBuy(amount, price string, currency goex.CurrencyPair) (*goex.Order, error) { +func (bo *Bigone) LimitBuy(amount, price string, currency goex.CurrencyPair, opt ...goex.LimitOrderOptionalParameter) (*goex.Order, error) { return bo.placeOrder(amount, price, currency, "LIMIT", "BID") } -func (bo *Bigone) LimitSell(amount, price string, currency goex.CurrencyPair) (*goex.Order, error) { +func (bo *Bigone) LimitSell(amount, price string, currency goex.CurrencyPair, opt ...goex.LimitOrderOptionalParameter) (*goex.Order, error) { return bo.placeOrder(amount, price, currency, "LIMIT", "ASK") } diff --git a/binance/Binance.go b/binance/Binance.go index a8171dd3..c7dbf991 100644 --- a/binance/Binance.go +++ b/binance/Binance.go @@ -398,11 +398,11 @@ func (bn *Binance) GetAccount() (*Account, error) { return &acc, nil } -func (bn *Binance) LimitBuy(amount, price string, currencyPair CurrencyPair) (*Order, error) { +func (bn *Binance) LimitBuy(amount, price string, currencyPair CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return bn.placeOrder(amount, price, currencyPair, "LIMIT", "BUY") } -func (bn *Binance) LimitSell(amount, price string, currencyPair CurrencyPair) (*Order, error) { +func (bn *Binance) LimitSell(amount, price string, currencyPair CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return bn.placeOrder(amount, price, currencyPair, "LIMIT", "SELL") } @@ -537,40 +537,6 @@ func (bn *Binance) GetUnfinishOrders(currencyPair CurrencyPair) ([]Order, error) return orders, nil } -func (bn *Binance) GetAllUnfinishOrders() ([]Order, error) { - params := url.Values{} - - bn.buildParamsSigned(¶ms) - path := bn.apiV3 + UNFINISHED_ORDERS_INFO + params.Encode() - - respmap, err := HttpGet3(bn.httpClient, path, map[string]string{"X-MBX-APIKEY": bn.accessKey}) - if err != nil { - return nil, err - } - - orders := make([]Order, 0) - for _, v := range respmap { - ord := v.(map[string]interface{}) - side := ord["side"].(string) - orderSide := SELL - if side == "BUY" { - orderSide = BUY - } - - ordId := ToInt(ord["orderId"]) - orders = append(orders, Order{ - OrderID: ToInt(ord["orderId"]), - OrderID2: strconv.Itoa(ordId), - Currency: bn.toCurrencyPair(ord["symbol"].(string)), - Price: ToFloat64(ord["price"]), - Amount: ToFloat64(ord["origQty"]), - Side: TradeSide(orderSide), - Status: ORDER_UNFINISH, - OrderTime: ToInt(ord["time"])}) - } - return orders, nil -} - func (bn *Binance) GetKlineRecords(currency CurrencyPair, period, size, since int) ([]Kline, error) { params := url.Values{} params.Set("symbol", currency.ToSymbol("")) @@ -662,6 +628,23 @@ func (bn *Binance) GetOrderHistorys(currency CurrencyPair, currentPage, pageSize orderSide = BUY } ordId := ToInt(ord["orderId"]) + status := ord["status"].(string) + var tradeStatus TradeStatus + switch status { + case "NEW": + tradeStatus = ORDER_UNFINISH + case "FILLED": + tradeStatus = ORDER_FINISH + case "PARTIALLY_FILLED": + tradeStatus = ORDER_PART_FINISH + case "CANCELED": + tradeStatus = ORDER_CANCEL + case "PENDING_CANCEL": + tradeStatus = ORDER_CANCEL_ING + case "REJECTED": + tradeStatus = ORDER_REJECT + } + orders = append(orders, Order{ OrderID: ToInt(ord["orderId"]), OrderID2: strconv.Itoa(ordId), @@ -669,7 +652,7 @@ func (bn *Binance) GetOrderHistorys(currency CurrencyPair, currentPage, pageSize Price: ToFloat64(ord["price"]), Amount: ToFloat64(ord["origQty"]), Side: TradeSide(orderSide), - Status: ORDER_UNFINISH, + Status: tradeStatus, OrderTime: ToInt(ord["time"])}) } return orders, nil diff --git a/binance/BinanceSwap.go b/binance/BinanceSwap.go index 00014735..181168d6 100644 --- a/binance/BinanceSwap.go +++ b/binance/BinanceSwap.go @@ -19,10 +19,6 @@ type BinanceSwap struct { Binance } -func (bs *BinanceSwap) LimitFuturesOrder(currencyPair CurrencyPair, contractType, price, amount string, openType int) (*FutureOrder, error) { - return bs.PlaceFutureOrder2(currencyPair, contractType, price, amount, openType, 0, 10) -} - func NewBinanceSwap(config *APIConfig) *BinanceSwap { if config.Endpoint == "" { config.Endpoint = baseUrl @@ -293,7 +289,7 @@ func (bs *BinanceSwap) Transfer(currency Currency, transferType int, amount floa return ToInt64(respmap["tranId"]), nil } -func (bs *BinanceSwap) PlaceFutureOrder(currencyPair CurrencyPair, contractType, price, amount string, openType, matchPrice, leverRate int) (string, error) { +func (bs *BinanceSwap) PlaceFutureOrder(currencyPair CurrencyPair, contractType, price, amount string, openType, matchPrice int, leverRate float64) (string, error) { fOrder, err := bs.PlaceFutureOrder2(currencyPair, contractType, price, amount, openType, matchPrice, leverRate) return fOrder.OrderID2, err } @@ -308,7 +304,7 @@ func (bs *BinanceSwap) PlaceFutureOrder(currencyPair CurrencyPair, contractType, * @param openType 1:开多 2:开空 3:平多 4:平空 * @param matchPrice 是否为对手价 0:不是 1:是 ,当取值为1时,price无效 */ -func (bs *BinanceSwap) PlaceFutureOrder2(currencyPair CurrencyPair, contractType, price, amount string, openType, matchPrice, leverRate int) (*FutureOrder, error) { +func (bs *BinanceSwap) PlaceFutureOrder2(currencyPair CurrencyPair, contractType, price, amount string, openType, matchPrice int, leverRate float64) (*FutureOrder, error) { fOrder := &FutureOrder{ Currency: currencyPair, ClientOid: GenerateOrderClientId(32), @@ -362,6 +358,14 @@ func (bs *BinanceSwap) PlaceFutureOrder2(currencyPair CurrencyPair, contractType return fOrder, nil } +func (bs *BinanceSwap) LimitFuturesOrder(currencyPair CurrencyPair, contractType, price, amount string, openType int, opt ...LimitOrderOptionalParameter) (*FutureOrder, error) { + return bs.PlaceFutureOrder2(currencyPair, contractType, price, amount, openType, 0, 10) +} + +func (bs *BinanceSwap) MarketFuturesOrder(currencyPair CurrencyPair, contractType, amount string, openType int) (*FutureOrder, error) { + return bs.PlaceFutureOrder2(currencyPair, contractType, "0", amount, openType, 1, 10) +} + /** * 取消订单 * @param symbol btc_usd:比特币 ltc_usd :莱特币 @@ -486,7 +490,7 @@ func (bs *BinanceSwap) GetFuturePosition(currencyPair CurrencyPair, contractType continue } p := FuturePosition{ - LeverRate: ToInt(cont["leverage"]), + LeverRate: ToFloat64(cont["leverage"]), Symbol: currencyPair, ForceLiquPrice: ToFloat64(cont["liquidationPrice"]), } diff --git a/binance/Binance_test.go b/binance/Binance_test.go index 75bea087..b4defdc6 100644 --- a/binance/Binance_test.go +++ b/binance/Binance_test.go @@ -23,7 +23,7 @@ var ba = NewWithConfig( }, Timeout: 10 * time.Second, }, - Endpoint: US_API_BASE_URL, + Endpoint: GLOBAL_API_BASE_URL, ApiKey: "q6y6Gr7fF3jSJLncpfn2PmAA0xu4XRiRFHpFkyJy3d7K68WUxY0Gt8rrajCDUfbI", ApiSecretKey: "AP8C2kh4RyISN3fpRCFMZJddf233XbPcYWQ1S7gBan3pGjCQg2JnyQFSJrIaNzRh", }) @@ -70,6 +70,7 @@ func TestBinance_GetUnfinishOrders(t *testing.T) { orders, err := ba.GetUnfinishOrders(goex.ETH_BTC) t.Log(orders, err) } + func TestBinance_GetKlineRecords(t *testing.T) { before := time.Now().Add(-time.Hour).Unix() * 1000 kline, _ := ba.GetKlineRecords(goex.ETH_BTC, goex.KLINE_PERIOD_5MIN, 100, int(before)) @@ -91,3 +92,7 @@ func TestBinance_SetTimeOffset(t *testing.T) { t.Log(ba.setTimeOffset()) t.Log(ba.timeOffset) } + +func TestBinance_GetOrderHistorys(t *testing.T) { + t.Log(ba.GetOrderHistorys(goex.BTC_USDT, 1, 1)) +} diff --git a/bitfinex/bitfinex.go b/bitfinex/bitfinex.go index 74338b31..ce2025e5 100644 --- a/bitfinex/bitfinex.go +++ b/bitfinex/bitfinex.go @@ -220,11 +220,11 @@ func (bfx *Bitfinex) placeOrder(orderType, side, amount, price string, pair Curr return order, nil } -func (bfx *Bitfinex) LimitBuy(amount, price string, currencyPair CurrencyPair) (*Order, error) { +func (bfx *Bitfinex) LimitBuy(amount, price string, currencyPair CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return bfx.placeOrder("exchange limit", "buy", amount, price, currencyPair) } -func (bfx *Bitfinex) LimitSell(amount, price string, currencyPair CurrencyPair) (*Order, error) { +func (bfx *Bitfinex) LimitSell(amount, price string, currencyPair CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return bfx.placeOrder("exchange limit", "sell", amount, price, currencyPair) } diff --git a/bithumb/bithumb.go b/bithumb/bithumb.go index 52b73eba..1b6f85c2 100644 --- a/bithumb/bithumb.go +++ b/bithumb/bithumb.go @@ -59,11 +59,11 @@ func (bit *Bithumb) placeOrder(side, amount, price string, pair CurrencyPair) (* Status: ORDER_UNFINISH}, nil } -func (bit *Bithumb) LimitBuy(amount, price string, currency CurrencyPair) (*Order, error) { +func (bit *Bithumb) LimitBuy(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return bit.placeOrder("bid", amount, price, currency) } -func (bit *Bithumb) LimitSell(amount, price string, currency CurrencyPair) (*Order, error) { +func (bit *Bithumb) LimitSell(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return bit.placeOrder("ask", amount, price, currency) } diff --git a/bitmex/bitmex.go b/bitmex/bitmex.go index a10e80bb..a95fe0ac 100644 --- a/bitmex/bitmex.go +++ b/bitmex/bitmex.go @@ -176,10 +176,14 @@ func (bm *bitmex) PlaceFutureOrder2(currencyPair CurrencyPair, contractType, pri return fOrder, nil } -func (bm *bitmex) LimitFuturesOrder(currencyPair CurrencyPair, contractType, price, amount string, openType int) (*FutureOrder, error) { +func (bm *bitmex) LimitFuturesOrder(currencyPair CurrencyPair, contractType, price, amount string, openType int, opt ...LimitOrderOptionalParameter) (*FutureOrder, error) { return bm.PlaceFutureOrder2(currencyPair, contractType, price, amount, openType, 0, 10) } +func (bm *bitmex) MarketFuturesOrder(currencyPair CurrencyPair, contractType, amount string, openType int) (*FutureOrder, error) { + return bm.PlaceFutureOrder2(currencyPair, contractType, "0", amount, openType, 1, 10) +} + func (bm *bitmex) FutureCancelOrder(currencyPair CurrencyPair, contractType, orderId string) (bool, error) { var param struct { OrderID string `json:"orderID,omitempty"` diff --git a/bitstamp/Bitstamp.go b/bitstamp/Bitstamp.go index 115013f6..e2690ea0 100644 --- a/bitstamp/Bitstamp.go +++ b/bitstamp/Bitstamp.go @@ -159,11 +159,11 @@ func (bitstamp *Bitstamp) placeMarketOrder(side string, pair CurrencyPair, amoun return bitstamp.placeOrder(side, pair, amount, "", urlStr) } -func (bitstamp *Bitstamp) LimitBuy(amount, price string, currency CurrencyPair) (*Order, error) { +func (bitstamp *Bitstamp) LimitBuy(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return bitstamp.placeLimitOrder("buy", currency, amount, price) } -func (bitstamp *Bitstamp) LimitSell(amount, price string, currency CurrencyPair) (*Order, error) { +func (bitstamp *Bitstamp) LimitSell(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return bitstamp.placeLimitOrder("sell", currency, amount, price) } diff --git a/bittrex/bittrex.go b/bittrex/bittrex.go index 525422f6..71f51cf1 100644 --- a/bittrex/bittrex.go +++ b/bittrex/bittrex.go @@ -1,11 +1,11 @@ package bittrex import ( + "errors" "fmt" . "github.com/nntaoli-project/goex" "net/http" "sort" - "errors" ) type Bittrex struct { @@ -19,10 +19,10 @@ func New(client *http.Client, accesskey, secretkey string) *Bittrex { return &Bittrex{client: client, accesskey: accesskey, secretkey: secretkey, baseUrl: "https://bittrex.com/api/v1.1"} } -func (bx *Bittrex) LimitBuy(amount, price string, currency CurrencyPair) (*Order, error) { +func (bx *Bittrex) LimitBuy(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { panic("not implement") } -func (bx *Bittrex) LimitSell(amount, price string, currency CurrencyPair) (*Order, error) { +func (bx *Bittrex) LimitSell(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { panic("not implement") } func (bx *Bittrex) MarketBuy(amount, price string, currency CurrencyPair) (*Order, error) { diff --git a/builder/APIBuilder.go b/builder/APIBuilder.go index 637c9004..ed304c83 100644 --- a/builder/APIBuilder.go +++ b/builder/APIBuilder.go @@ -24,7 +24,6 @@ import ( "time" "github.com/nntaoli-project/goex/coinex" - "github.com/nntaoli-project/goex/gateio" "github.com/nntaoli-project/goex/gdax" "github.com/nntaoli-project/goex/hitbtc" "github.com/nntaoli-project/goex/huobi" @@ -233,8 +232,6 @@ func (builder *APIBuilder) Build(exName string) (api API) { _api = bithumb.New(builder.client, builder.apiKey, builder.secretkey) case GDAX: _api = gdax.New(builder.client, builder.apiKey, builder.secretkey) - case GATEIO: - _api = gateio.New(builder.client, builder.apiKey, builder.secretkey) case ZB: _api = zb.New(builder.client, builder.apiKey, builder.secretkey) case COINEX: diff --git a/coinbene/CoinbeneSwap.go b/coinbene/CoinbeneSwap.go index 421582a2..26602381 100644 --- a/coinbene/CoinbeneSwap.go +++ b/coinbene/CoinbeneSwap.go @@ -21,7 +21,7 @@ type baseResp struct { type CoinbeneOrder struct { OrderId string `json:"orderId"` Direction string `json:"direction"` - Leverage int `json:"leverage,string"` + Leverage float64 `json:"leverage,string"` Symbol string `json:"symbol"` OrderType string `json:"orderType"` Quantity float64 `json:"quantity,string"` @@ -42,6 +42,9 @@ func NewCoinbeneSwap(config APIConfig) *CoinbeneSwap { if config.Endpoint == "" { config.Endpoint = "http://openapi-contract.coinbene.com" } + if config.Lever <= 0 { + config.Lever = 10 + } if strings.HasSuffix(config.Endpoint, "/") { config.Endpoint = config.Endpoint[0 : len(config.Endpoint)-1] } @@ -160,7 +163,7 @@ func (swap *CoinbeneSwap) GetFutureUserinfo(currencyPair ...CurrencyPair) (*Futu return acc, nil } -func (swap *CoinbeneSwap) PlaceFutureOrder(currencyPair CurrencyPair, contractType, price, amount string, openType, matchPrice, leverRate int) (string, error) { +func (swap *CoinbeneSwap) PlaceFutureOrder(currencyPair CurrencyPair, contractType, price, amount string, openType, matchPrice int, leverRate float64) (string, error) { var param struct { Symbol string `json:"symbol"` Leverage string `json:"leverage"` @@ -192,7 +195,7 @@ func (swap *CoinbeneSwap) PlaceFutureOrder(currencyPair CurrencyPair, contractTy return data.orderId, nil } -func (swap *CoinbeneSwap) LimitFuturesOrder(currencyPair CurrencyPair, contractType, price, amount string, openType int) (*FutureOrder, error) { +func (swap *CoinbeneSwap) LimitFuturesOrder(currencyPair CurrencyPair, contractType, price, amount string, openType int, opt ...LimitOrderOptionalParameter) (*FutureOrder, error) { orderId, err := swap.PlaceFutureOrder(currencyPair, contractType, price, amount, openType, 0, 10) return &FutureOrder{ Currency: currencyPair, @@ -204,6 +207,10 @@ func (swap *CoinbeneSwap) LimitFuturesOrder(currencyPair CurrencyPair, contractT }, err } +func (swap *CoinbeneSwap) MarketFuturesOrder(currencyPair CurrencyPair, contractType, amount string, openType int) (*FutureOrder, error) { + panic("not support the market order") +} + func (swap *CoinbeneSwap) FutureCancelOrder(currencyPair CurrencyPair, contractType, orderId string) (bool, error) { var param struct { OrderId string `json:"orderId"` @@ -222,7 +229,7 @@ func (swap *CoinbeneSwap) GetFuturePosition(currencyPair CurrencyPair, contractT AvailableQuantity float64 `json:"availableQuantity,string"` AveragePrice float64 `json:"averagePrice,string"` CreateTime time.Time `json:"createTime"` - Leverage int `json:"leverage,string"` + Leverage float64 `json:"leverage,string"` LiquidationPrice float64 `json:"liquidationPrice,string"` RealisedPnl float64 `json:"realisedPnl,string"` UnrealisedPnl float64 `json:"unrealisedPnl,string"` diff --git a/coinbig/coinbig.go b/coinbig/coinbig.go index 8a3b6256..9feabc71 100644 --- a/coinbig/coinbig.go +++ b/coinbig/coinbig.go @@ -166,11 +166,11 @@ func (cb *CoinBig) placeOrder(amount, price string, pair CurrencyPair, orderType OrderTime: int(time.Now().Unix())}, nil } -func (cb *CoinBig) LimitBuy(amount, price string, currencyPair CurrencyPair) (*Order, error) { +func (cb *CoinBig) LimitBuy(amount, price string, currencyPair CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return cb.placeOrder(amount, price, currencyPair, "limit", "buy") } -func (cb *CoinBig) LimitSell(amount, price string, currencyPair CurrencyPair) (*Order, error) { +func (cb *CoinBig) LimitSell(amount, price string, currencyPair CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return cb.placeOrder(amount, price, currencyPair, "limit", "sell") } diff --git a/coinex/coinex.go b/coinex/coinex.go index 9dfdeedb..499b59ad 100644 --- a/coinex/coinex.go +++ b/coinex/coinex.go @@ -103,11 +103,11 @@ func (coinex *CoinEx) placeLimitOrder(side, amount, price string, pair CurrencyP return &order, nil } -func (coinex *CoinEx) LimitBuy(amount, price string, currency CurrencyPair) (*Order, error) { +func (coinex *CoinEx) LimitBuy(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return coinex.placeLimitOrder("buy", amount, price, currency) } -func (coinex *CoinEx) LimitSell(amount, price string, currency CurrencyPair) (*Order, error) { +func (coinex *CoinEx) LimitSell(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return coinex.placeLimitOrder("sell", amount, price, currency) } diff --git a/exx/exx.go b/exx/exx.go index 20ece63e..643c0c48 100644 --- a/exx/exx.go +++ b/exx/exx.go @@ -227,11 +227,11 @@ func (exx *Exx) placeOrder(amount, price string, currency CurrencyPair, tradeTyp return order, nil } -func (exx *Exx) LimitBuy(amount, price string, currency CurrencyPair) (*Order, error) { +func (exx *Exx) LimitBuy(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return exx.placeOrder(amount, price, currency, 1) } -func (exx *Exx) LimitSell(amount, price string, currency CurrencyPair) (*Order, error) { +func (exx *Exx) LimitSell(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return exx.placeOrder(amount, price, currency, 0) } diff --git a/gateio/gateio.go b/gateio/gateio.go deleted file mode 100644 index a5aed745..00000000 --- a/gateio/gateio.go +++ /dev/null @@ -1,112 +0,0 @@ -package gateio - -import ( - "fmt" - . "github.com/nntaoli-project/goex" - "net/http" - "sort" - "strings" -) - -var ( - marketBaseUrl = "http://data.gate.io/api2/1" -) - -type Gate struct { - client *http.Client - accesskey, - secretkey string -} - -func New(client *http.Client, accesskey, secretkey string) *Gate { - return &Gate{client: client, accesskey: accesskey, secretkey: secretkey} -} - -func (g *Gate) LimitBuy(amount, price string, currency CurrencyPair) (*Order, error) { - panic("not implement") -} -func (g *Gate) LimitSell(amount, price string, currency CurrencyPair) (*Order, error) { - panic("not implement") -} -func (g *Gate) MarketBuy(amount, price string, currency CurrencyPair) (*Order, error) { - panic("not implement") -} -func (g *Gate) MarketSell(amount, price string, currency CurrencyPair) (*Order, error) { - panic("not implement") -} -func (g *Gate) CancelOrder(orderId string, currency CurrencyPair) (bool, error) { - panic("not implement") -} -func (g *Gate) GetOneOrder(orderId string, currency CurrencyPair) (*Order, error) { - panic("not implement") -} -func (g *Gate) GetUnfinishOrders(currency CurrencyPair) ([]Order, error) { - panic("not implement") -} -func (g *Gate) GetOrderHistorys(currency CurrencyPair, currentPage, pageSize int) ([]Order, error) { - panic("not implement") -} -func (g *Gate) GetAccount() (*Account, error) { - panic("not implement") -} - -func (g *Gate) GetTicker(currency CurrencyPair) (*Ticker, error) { - uri := fmt.Sprintf("%s/ticker/%s", marketBaseUrl, strings.ToLower(currency.ToSymbol("_"))) - - resp, err := HttpGet(g.client, uri) - if err != nil { - errCode := HTTP_ERR_CODE - errCode.OriginErrMsg = err.Error() - return nil, errCode - } - - return &Ticker{ - Last: ToFloat64(resp["last"]), - Sell: ToFloat64(resp["lowestAsk"]), - Buy: ToFloat64(resp["highestBid"]), - High: ToFloat64(resp["high24hr"]), - Low: ToFloat64(resp["low24hr"]), - Vol: ToFloat64(resp["quoteVolume"]), - }, nil -} - -func (g *Gate) GetDepth(size int, currency CurrencyPair) (*Depth, error) { - resp, err := HttpGet(g.client, fmt.Sprintf("%s/orderBook/%s", marketBaseUrl, currency.ToSymbol("_"))) - if err != nil { - errCode := HTTP_ERR_CODE - errCode.OriginErrMsg = err.Error() - return nil, errCode - } - - bids, _ := resp["bids"].([]interface{}) - asks, _ := resp["asks"].([]interface{}) - - dep := new(Depth) - - for _, v := range bids { - r := v.([]interface{}) - dep.BidList = append(dep.BidList, DepthRecord{ToFloat64(r[0]), ToFloat64(r[1])}) - } - - for _, v := range asks { - r := v.([]interface{}) - dep.AskList = append(dep.AskList, DepthRecord{ToFloat64(r[0]), ToFloat64(r[1])}) - } - - sort.Sort(sort.Reverse(dep.AskList)) - - return dep, nil -} - -func (g *Gate) GetKlineRecords(currency CurrencyPair, period, size, since int) ([]Kline, error) { - panic("not implement") -} - -//非个人,整个交易所的交易记录 -func (g *Gate) GetTrades(currencyPair CurrencyPair, since int64) ([]Trade, error) { - panic("not implement") -} - -func (g *Gate) GetExchangeName() string { - return GATEIO -} diff --git a/gateio/gateio_test.go b/gateio/gateio_test.go deleted file mode 100644 index bb5dc689..00000000 --- a/gateio/gateio_test.go +++ /dev/null @@ -1,23 +0,0 @@ -package gateio - -import ( - "github.com/nntaoli-project/goex" - "net/http" - "testing" -) - -var gate = New(http.DefaultClient, "", "") - -func TestGate_GetTicker(t *testing.T) { - ticker, err := gate.GetTicker(goex.BTC_USDT) - t.Log("err=>", err) - t.Log("ticker=>", ticker) -} - -func TestGate_GetDepth(t *testing.T) { - dep, err := gate.GetDepth(1, goex.BTC_USDT) - - t.Log("err=>", err) - t.Log("asks=>", dep.AskList) - t.Log("bids=>", dep.BidList) -} diff --git a/gdax/gdax.go b/gdax/gdax.go index 91b93f78..462242f9 100644 --- a/gdax/gdax.go +++ b/gdax/gdax.go @@ -24,10 +24,10 @@ func New(client *http.Client, accesskey, secretkey string) *Gdax { return &Gdax{client, "https://api.gdax.com", accesskey, secretkey} } -func (g *Gdax) LimitBuy(amount, price string, currency CurrencyPair) (*Order, error) { +func (g *Gdax) LimitBuy(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { panic("not implement") } -func (g *Gdax) LimitSell(amount, price string, currency CurrencyPair) (*Order, error) { +func (g *Gdax) LimitSell(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { panic("not implement") } func (g *Gdax) MarketBuy(amount, price string, currency CurrencyPair) (*Order, error) { diff --git a/hitbtc/Hitbtc.go b/hitbtc/Hitbtc.go index 36cb9ef1..ff731b88 100644 --- a/hitbtc/Hitbtc.go +++ b/hitbtc/Hitbtc.go @@ -214,11 +214,11 @@ func (hitbtc *Hitbtc) placeOrder(ty goex.TradeSide, amount, price string, curren return hitbtc.toOrder(resp), nil } -func (hitbtc *Hitbtc) LimitBuy(amount, price string, currency goex.CurrencyPair) (*goex.Order, error) { +func (hitbtc *Hitbtc) LimitBuy(amount, price string, currency goex.CurrencyPair, opt ...goex.LimitOrderOptionalParameter) (*goex.Order, error) { return hitbtc.placeOrder(goex.BUY, amount, price, currency) } -func (hitbtc *Hitbtc) LimitSell(amount, price string, currency goex.CurrencyPair) (*goex.Order, error) { +func (hitbtc *Hitbtc) LimitSell(amount, price string, currency goex.CurrencyPair, opt ...goex.LimitOrderOptionalParameter) (*goex.Order, error) { return hitbtc.placeOrder(goex.SELL, amount, price, currency) } diff --git a/huobi/Hbdm.go b/huobi/Hbdm.go index 31485d60..78ef73f7 100644 --- a/huobi/Hbdm.go +++ b/huobi/Hbdm.go @@ -27,7 +27,7 @@ type OrderInfo struct { OrderPriceType string `json:"order_price_type"` Direction string `json:"direction"` Offset string `json:"offset"` - LeverRate int `json:"lever_rate"` + LeverRate float64 `json:"lever_rate"` OrderId int64 `json:"order_id"` ClientOrderId int64 `json:"client_order_id"` OrderSource string `json:"order_source"` @@ -121,6 +121,9 @@ func NewHbdm(conf *APIConfig) *Hbdm { if conf.Endpoint == "" { conf.Endpoint = defaultBaseUrl } + if conf.Lever <= 0 { + conf.Lever = 10 + } hbdmInit() return &Hbdm{conf} } @@ -181,7 +184,7 @@ func (dm *Hbdm) GetFuturePosition(currencyPair CurrencyPair, contractType string ProfitRate float64 `json:"profit_rate"` Profit float64 `json:"profit"` PositionMargin float64 `json:"position_margin"` - LeverRate int `json:"lever_rate"` + LeverRate float64 `json:"lever_rate"` Direction string `json:"direction"` } @@ -201,7 +204,7 @@ func (dm *Hbdm) GetFuturePosition(currencyPair CurrencyPair, contractType string if d.ContractType != contractType { continue } - + switch d.Direction { case "buy": positions = append(positions, FuturePosition{ @@ -231,12 +234,12 @@ func (dm *Hbdm) GetFuturePosition(currencyPair CurrencyPair, contractType string return positions, nil } -func (dm *Hbdm) PlaceFutureOrder(currencyPair CurrencyPair, contractType, price, amount string, openType, matchPrice, leverRate int) (string, error) { +func (dm *Hbdm) PlaceFutureOrder(currencyPair CurrencyPair, contractType, price, amount string, openType, matchPrice int, leverRate float64) (string, error) { fOrder, err := dm.PlaceFutureOrder2(currencyPair, contractType, price, amount, openType, matchPrice, leverRate) return fOrder.OrderID2, err } -func (dm *Hbdm) PlaceFutureOrder2(currencyPair CurrencyPair, contractType, price, amount string, openType, matchPrice, leverRate int) (*FutureOrder, error) { +func (dm *Hbdm) PlaceFutureOrder2(currencyPair CurrencyPair, contractType, price, amount string, openType, matchPrice int, leverRate float64, opt ...LimitOrderOptionalParameter) (*FutureOrder, error) { var data struct { OrderId int64 `json:"order_id"` COrderId int64 `json:"client_order_id"` @@ -255,7 +258,18 @@ func (dm *Hbdm) PlaceFutureOrder2(currencyPair CurrencyPair, contractType, price if matchPrice == 1 { params.Set("order_price_type", "opponent") //对手价下单 } else { - params.Set("order_price_type", "limit") + orderPriceType := "limit" + if len(opt) > 0 { + switch opt[0] { + case Fok: + orderPriceType = "fok" + case Ioc: + orderPriceType = "ioc" + case PostOnly: + orderPriceType = "post_only" + } + } + params.Set("order_price_type", orderPriceType) params.Add("price", dm.formatPriceSize(contractType, currencyPair.CurrencyA, price)) } @@ -283,8 +297,12 @@ func (dm *Hbdm) PlaceFutureOrder2(currencyPair CurrencyPair, contractType, price return fOrd, err } -func (dm *Hbdm) LimitFuturesOrder(currencyPair CurrencyPair, contractType, price, amount string, openType int) (*FutureOrder, error) { - return dm.PlaceFutureOrder2(currencyPair, contractType, price, amount, openType, 0, 10) +func (dm *Hbdm) LimitFuturesOrder(currencyPair CurrencyPair, contractType, price, amount string, openType int, opt ...LimitOrderOptionalParameter) (*FutureOrder, error) { + return dm.PlaceFutureOrder2(currencyPair, contractType, price, amount, openType, 0, dm.config.Lever) +} + +func (dm *Hbdm) MarketFuturesOrder(currencyPair CurrencyPair, contractType, amount string, openType int) (*FutureOrder, error) { + return dm.PlaceFutureOrder2(currencyPair, contractType, "0", amount, openType, 1, dm.config.Lever) } func (dm *Hbdm) FutureCancelOrder(currencyPair CurrencyPair, contractType, orderId string) (bool, error) { diff --git a/huobi/HuobiPro.go b/huobi/HuobiPro.go index 2f2a49eb..484d3de0 100644 --- a/huobi/HuobiPro.go +++ b/huobi/HuobiPro.go @@ -264,8 +264,21 @@ func (hbpro *HuoBiPro) placeOrder(amount, price string, pair CurrencyPair, order return respmap["data"].(string), nil } -func (hbpro *HuoBiPro) LimitBuy(amount, price string, currency CurrencyPair) (*Order, error) { - orderId, err := hbpro.placeOrder(amount, price, currency, "buy-limit") +func (hbpro *HuoBiPro) LimitBuy(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { + orderTy := "buy-limit" + if len(opt) > 0 { + switch opt[0] { + case PostOnly: + orderTy = "buy-limit-maker" + case Ioc: + orderTy = "buy-ioc" + case Fok: + orderTy = "buy-limit-fok" + default: + Log.Error("limit order optional parameter error ,opt= ", opt[0]) + } + } + orderId, err := hbpro.placeOrder(amount, price, currency, orderTy) if err != nil { return nil, err } @@ -278,8 +291,21 @@ func (hbpro *HuoBiPro) LimitBuy(amount, price string, currency CurrencyPair) (*O Side: BUY}, nil } -func (hbpro *HuoBiPro) LimitSell(amount, price string, currency CurrencyPair) (*Order, error) { - orderId, err := hbpro.placeOrder(amount, price, currency, "sell-limit") +func (hbpro *HuoBiPro) LimitSell(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { + orderTy := "sell-limit" + if len(opt) > 0 { + switch opt[0] { + case PostOnly: + orderTy = "sell-limit-maker" + case Ioc: + orderTy = "sell-ioc" + case Fok: + orderTy = "sell-limit-fok" + default: + Log.Error("limit order optional parameter error ,opt= ", opt[0]) + } + } + orderId, err := hbpro.placeOrder(amount, price, currency, orderTy) if err != nil { return nil, err } diff --git a/kraken/Kraken.go b/kraken/Kraken.go index 9acea9c9..34ed1b05 100644 --- a/kraken/Kraken.go +++ b/kraken/Kraken.go @@ -75,11 +75,11 @@ func (k *Kraken) placeOrder(orderType, side, amount, price string, pair Currency Status: ORDER_UNFINISH}, nil } -func (k *Kraken) LimitBuy(amount, price string, currency CurrencyPair) (*Order, error) { +func (k *Kraken) LimitBuy(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return k.placeOrder("limit", "buy", amount, price, currency) } -func (k *Kraken) LimitSell(amount, price string, currency CurrencyPair) (*Order, error) { +func (k *Kraken) LimitSell(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return k.placeOrder("limit", "sell", amount, price, currency) } diff --git a/kucoin/kucoin.go b/kucoin/kucoin.go index 72e7aa36..e9c726fd 100644 --- a/kucoin/kucoin.go +++ b/kucoin/kucoin.go @@ -91,7 +91,7 @@ func (kc *KuCoin) GetTicker(currency CurrencyPair) (*Ticker, error) { return &ticker, nil } -func (kc *KuCoin) LimitBuy(amount, price string, currency CurrencyPair) (*Order, error) { +func (kc *KuCoin) LimitBuy(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { clientID := GenerateOrderClientId(32) in := kucoin.CreateOrderModel{ ClientOid: clientID, @@ -121,7 +121,7 @@ func (kc *KuCoin) LimitBuy(amount, price string, currency CurrencyPair) (*Order, return &order, nil } -func (kc *KuCoin) LimitSell(amount, price string, currency CurrencyPair) (*Order, error) { +func (kc *KuCoin) LimitSell(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { clientID := GenerateOrderClientId(32) in := kucoin.CreateOrderModel{ ClientOid: clientID, diff --git a/okex/OKEx.go b/okex/OKEx.go index 1cd8cadb..fd202caa 100644 --- a/okex/OKEx.go +++ b/okex/OKEx.go @@ -129,12 +129,12 @@ func (ok *OKEx) IsoTime() string { return iso } -func (ok *OKEx) LimitBuy(amount, price string, currency CurrencyPair) (*Order, error) { - return ok.OKExSpot.LimitBuy(amount, price, currency) +func (ok *OKEx) LimitBuy(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { + return ok.OKExSpot.LimitBuy(amount, price, currency, opt...) } -func (ok *OKEx) LimitSell(amount, price string, currency CurrencyPair) (*Order, error) { - return ok.OKExSpot.LimitSell(amount, price, currency) +func (ok *OKEx) LimitSell(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { + return ok.OKExSpot.LimitSell(amount, price, currency, opt...) } func (ok *OKEx) MarketBuy(amount, price string, currency CurrencyPair) (*Order, error) { diff --git a/okex/OKExFuture.go b/okex/OKExFuture.go index 6a02e1c1..128bafa5 100644 --- a/okex/OKExFuture.go +++ b/okex/OKExFuture.go @@ -399,7 +399,7 @@ func (ok *OKExFuture) PlaceFutureOrder2(matchPrice int, ord *FutureOrder) (*Futu return ord, nil } -func (ok *OKExFuture) PlaceFutureOrder(currencyPair CurrencyPair, contractType, price, amount string, openType, matchPrice, leverRate int) (string, error) { +func (ok *OKExFuture) PlaceFutureOrder(currencyPair CurrencyPair, contractType, price, amount string, openType, matchPrice int, leverRate float64) (string, error) { fOrder, err := ok.PlaceFutureOrder2(matchPrice, &FutureOrder{ Price: ToFloat64(price), Amount: ToFloat64(amount), @@ -410,13 +410,35 @@ func (ok *OKExFuture) PlaceFutureOrder(currencyPair CurrencyPair, contractType, return fOrder.OrderID2, err } -func (ok *OKExFuture) LimitFuturesOrder(currencyPair CurrencyPair, contractType, price, amount string, openType int) (*FutureOrder, error) { - return ok.PlaceFutureOrder2(0, &FutureOrder{ +func (ok *OKExFuture) LimitFuturesOrder(currencyPair CurrencyPair, contractType, price, amount string, openType int, opt ...LimitOrderOptionalParameter) (*FutureOrder, error) { + ord := &FutureOrder{ Currency: currencyPair, Price: ToFloat64(price), Amount: ToFloat64(amount), OType: openType, ContractName: contractType, + } + + if len(opt) > 0 { + switch opt[0] { + case PostOnly: + ord.OrderType = 1 + case Fok: + ord.OrderType = 2 + case Ioc: + ord.OrderType = 3 + } + } + + return ok.PlaceFutureOrder2(0, ord) +} + +func (ok *OKExFuture) MarketFuturesOrder(currencyPair CurrencyPair, contractType, amount string, openType int) (*FutureOrder, error) { + return ok.PlaceFutureOrder2(1, &FutureOrder{ + Currency: currencyPair, + Amount: ToFloat64(amount), + OType: openType, + ContractName: contractType, }) } @@ -451,7 +473,7 @@ func (ok *OKExFuture) GetFuturePosition(currencyPair CurrencyPair, contractType LongPnlRatio float64 `json:"long_pnl_ratio,string"` LongUnrealisedPnl float64 `json:"long_unrealised_pnl,string"` RealisedPnl float64 `json:"realised_pnl,string"` - Leverage int `json:"leverage,string"` + Leverage float64 `json:"leverage,string"` ShortQty float64 `json:"short_qty,string"` ShortAvailQty float64 `json:"short_avail_qty,string"` ShortAvgCost float64 `json:"short_avg_cost,string"` @@ -498,6 +520,8 @@ func (ok *OKExFuture) GetFuturePosition(currencyPair CurrencyPair, contractType ForceLiquPrice: pos.LiquidationPrice, LeverRate: pos.Leverage, CreateDate: pos.CreatedAt.Unix(), + ShortPnlRatio: pos.ShortPnlRatio, + LongPnlRatio: pos.LongPnlRatio, }) } @@ -603,9 +627,9 @@ func (ok *OKExFuture) GetDeliveryTime() (int, int, int, int) { /** since : 单位秒,开始时间 */ -func (ok *OKExFuture) GetKlineRecords(contract_type string, currency CurrencyPair, period, size, since int) ([]FutureKline, error) { +func (ok *OKExFuture) GetKlineRecords(contractType string, currency CurrencyPair, period, size, since int) ([]FutureKline, error) { urlPath := "/api/futures/v3/instruments/%s/candles?start=%s&granularity=%d" - contractId := ok.GetFutureContractId(currency, contract_type) + contractId := ok.GetFutureContractId(currency, contractType) sinceTime := time.Unix(int64(since), 0).UTC() if since/int(time.Second) != 1 { //如果不为秒,转为秒 @@ -641,7 +665,46 @@ func (ok *OKExFuture) GetKlineRecords(contract_type string, currency CurrencyPai return klines, nil } -func (ok *OKExFuture) GetTrades(contract_type string, currencyPair CurrencyPair, since int64) ([]Trade, error) { +/** + since : 单位秒,开始时间 + to : 单位秒,结束时间 +*/ +func (ok *OKExFuture) GetKlineRecordsByRange(contractType string, currency CurrencyPair, period, since, to int) ([]FutureKline, error) { + urlPath := "/api/futures/v3/instruments/%s/candles?start=%s&end=%s&granularity=%d" + contractId := ok.GetFutureContractId(currency, contractType) + sinceTime := time.Unix(int64(since), 0).UTC() + toTime := time.Unix(int64(to), 0).UTC() + + granularity := adaptKLinePeriod(KlinePeriod(period)) + if granularity == -1 { + return nil, errors.New("kline period parameter is error") + } + + var response [][]interface{} + err := ok.DoRequest("GET", fmt.Sprintf(urlPath, contractId, sinceTime.Format(time.RFC3339), toTime.Format(time.RFC3339), granularity), "", &response) + if err != nil { + return nil, err + } + + var klines []FutureKline + for _, itm := range response { + t, _ := time.Parse(time.RFC3339, fmt.Sprint(itm[0])) + klines = append(klines, FutureKline{ + Kline: &Kline{ + Timestamp: t.Unix(), + Pair: currency, + Open: ToFloat64(itm[1]), + High: ToFloat64(itm[2]), + Low: ToFloat64(itm[3]), + Close: ToFloat64(itm[4]), + Vol: ToFloat64(itm[5])}, + Vol2: ToFloat64(itm[6])}) + } + + return klines, nil +} + +func (ok *OKExFuture) GetTrades(contractType string, currencyPair CurrencyPair, since int64) ([]Trade, error) { panic("") } diff --git a/okex/OKExFuturesWs.go b/okex/OKExFuturesWs.go index 2de0cb47..d1e88921 100644 --- a/okex/OKExFuturesWs.go +++ b/okex/OKExFuturesWs.go @@ -182,7 +182,8 @@ func (okV3Ws *OKExV3FuturesWs) handle(channel string, data json.RawMessage) erro } ) - if strings.Contains(channel, "futures/candle") { + if strings.Contains(channel, "futures/candle") || + strings.Contains(channel, "swap/candle") { ch = "candle" } else { ch, err = okV3Ws.v3Ws.parseChannel(channel) diff --git a/okex/OKExSpot.go b/okex/OKExSpot.go index 2f111bb3..60d813e7 100644 --- a/okex/OKExSpot.go +++ b/okex/OKExSpot.go @@ -162,8 +162,12 @@ func (ok *OKExSpot) PlaceOrder(ty string, ord *Order) (*Order, error) { return ord, nil } -func (ok *OKExSpot) LimitBuy(amount, price string, currency CurrencyPair) (*Order, error) { - return ok.PlaceOrder("limit", &Order{ +func (ok *OKExSpot) LimitBuy(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { + ty := "limit" + if len(opt) > 0 { + ty = opt[0].String() + } + return ok.PlaceOrder(ty, &Order{ Price: ToFloat64(price), Amount: ToFloat64(amount), Currency: currency, @@ -171,8 +175,12 @@ func (ok *OKExSpot) LimitBuy(amount, price string, currency CurrencyPair) (*Orde }) } -func (ok *OKExSpot) LimitSell(amount, price string, currency CurrencyPair) (*Order, error) { - return ok.PlaceOrder("limit", &Order{ +func (ok *OKExSpot) LimitSell(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { + ty := "limit" + if len(opt) > 0 { + ty = opt[0].String() + } + return ok.PlaceOrder(ty, &Order{ Price: ToFloat64(price), Amount: ToFloat64(amount), Currency: currency, @@ -235,6 +243,7 @@ type OrderResponse struct { FilledNotional string `json:"filled_notional"` PriceAvg string `json:"price_avg"` State int `json:"state,string"` + Fee string `json:"fee"` OrderType int `json:"order_type,string"` Timestamp string `json:"timestamp"` } @@ -247,7 +256,8 @@ func (ok *OKExSpot) adaptOrder(response OrderResponse) *Order { Amount: response.Size, AvgPrice: ToFloat64(response.PriceAvg), DealAmount: ToFloat64(response.FilledSize), - Status: ok.adaptOrderState(response.State)} + Status: ok.adaptOrderState(response.State), + Fee: ToFloat64(response.Fee)} switch response.Side { case "buy": diff --git a/okex/OKExSwap.go b/okex/OKExSwap.go index 0f8e9b18..e630398c 100644 --- a/okex/OKExSwap.go +++ b/okex/OKExSwap.go @@ -76,6 +76,9 @@ const ( GET_TICKER = "/api/swap/v3/instruments/%s/ticker" GET_ALL_TICKER = "/api/swap/v3/instruments/ticker" GET_UNFINISHED_ORDERS = "/api/swap/v3/orders/%s?status=%d&limit=%d" + PLACE_ALGO_ORDER = "/api/swap/v3/order_algo" + CANCEL_ALGO_ORDER = "/api/swap/v3/cancel_algos" + GET_ALGO_ORDER = "/api/swap/v3/order_algo/%s?order_type=%d&" ) type BaseResponse struct { @@ -265,6 +268,7 @@ type BasePlaceOrderInfo struct { MatchPrice string `json:"match_price"` Type string `json:"type"` Size string `json:"size"` + OrderType string `json:"order_type"` } type PlaceOrderInfo struct { @@ -277,14 +281,14 @@ type PlaceOrdersInfo struct { OrderData []*BasePlaceOrderInfo `json:"order_data"` } -func (ok *OKExSwap) PlaceFutureOrder(currencyPair CurrencyPair, contractType, price, amount string, openType, matchPrice, leverRate int) (string, error) { - fOrder, err := ok.PlaceFutureOrder2(currencyPair, contractType, price, amount, openType, matchPrice, leverRate) +func (ok *OKExSwap) PlaceFutureOrder(currencyPair CurrencyPair, contractType, price, amount string, openType, matchPrice int, leverRate float64) (string, error) { + fOrder, err := ok.PlaceFutureOrder2(currencyPair, contractType, price, amount, openType, matchPrice) return fOrder.OrderID2, err } -func (ok *OKExSwap) PlaceFutureOrder2(currencyPair CurrencyPair, contractType, price, amount string, openType, matchPrice, leverRate int) (*FutureOrder, error) { +func (ok *OKExSwap) PlaceFutureOrder2(currencyPair CurrencyPair, contractType, price, amount string, openType, matchPrice int, opt ...LimitOrderOptionalParameter) (*FutureOrder, error) { cid := GenerateOrderClientId(32) - reqBody, _, _ := ok.OKEx.BuildRequestBody(PlaceOrderInfo{ + param := PlaceOrderInfo{ BasePlaceOrderInfo{ ClientOid: cid, Price: price, @@ -292,7 +296,20 @@ func (ok *OKExSwap) PlaceFutureOrder2(currencyPair CurrencyPair, contractType, p Type: fmt.Sprint(openType), Size: amount}, ok.adaptContractType(currencyPair), - }) + } + + if len(opt) > 0 { + switch opt[0] { + case PostOnly: + param.OrderType = "1" + case Fok: + param.OrderType = "2" + case Ioc: + param.OrderType = "3" + } + } + + reqBody, _, _ := ok.OKEx.BuildRequestBody(param) fOrder := &FutureOrder{ ClientOid: cid, @@ -323,8 +340,12 @@ func (ok *OKExSwap) PlaceFutureOrder2(currencyPair CurrencyPair, contractType, p return fOrder, nil } -func (ok *OKExSwap) LimitFuturesOrder(currencyPair CurrencyPair, contractType, price, amount string, openType int) (*FutureOrder, error) { - return ok.PlaceFutureOrder2(currencyPair, contractType, price, amount, openType, 0, 10) +func (ok *OKExSwap) LimitFuturesOrder(currencyPair CurrencyPair, contractType, price, amount string, openType int, opt ...LimitOrderOptionalParameter) (*FutureOrder, error) { + return ok.PlaceFutureOrder2(currencyPair, contractType, price, amount, openType, 0, opt...) +} + +func (ok *OKExSwap) MarketFuturesOrder(currencyPair CurrencyPair, contractType, amount string, openType int) (*FutureOrder, error) { + return ok.PlaceFutureOrder2(currencyPair, contractType, "0", amount, openType, 1) } func (ok *OKExSwap) FutureCancelOrder(currencyPair CurrencyPair, contractType, orderId string) (bool, error) { @@ -490,6 +511,8 @@ func (ok *OKExSwap) GetFuturePosition(currencyPair CurrencyPair, contractType st positions[0].SellPriceAvg = sellPosition.AvgCost positions[0].SellProfitReal = sellPosition.RealizedPnl positions[0].SellPriceCost = sellPosition.SettlementPrice + + positions[0].LeverRate = ToFloat64(sellPosition.Leverage) } return positions, nil } @@ -681,3 +704,148 @@ func (ok *OKExSwap) SetMarginLevel(currencyPair CurrencyPair, level, marginMode } return &resp, nil } + +//委托策略下单 algo_type 1:限价 2:市场价;触发价格类型,默认是限价;为市场价时,委托价格不必填; +func (ok *OKExSwap) PlaceFutureAlgoOrder(ord *FutureOrder) (*FutureOrder, error) { + var param struct { + InstrumentId string `json:"instrument_id"` + Type int `json:"type"` + OrderType int `json:"order_type"` //1:止盈止损 2:跟踪委托 3:冰山委托 4:时间加权 + Size string `json:"size"` + TriggerPrice string `json:"trigger_price"` + AlgoPrice string `json:"algo_price"` + AlgoType string `json:"algo_type"` + } + + var response struct { + ErrorMessage string `json:"error_message"` + ErrorCode string `json:"error_code"` + DetailMsg string `json:"detail_msg"` + + Data struct { + Result string `json:"result"` + ErrorMessage string `json:"error_message"` + ErrorCode string `json:"error_code"` + AlgoId string `json:"algo_id"` + InstrumentId string `json:"instrument_id"` + OrderType int `json:"order_type"` + } `json:"data"` + } + if ord == nil { + return nil, errors.New("ord param is nil") + } + param.InstrumentId = ok.adaptContractType(ord.Currency) + param.Type = ord.OType + param.OrderType = ord.OrderType + param.AlgoType = fmt.Sprint(ord.AlgoType) + param.TriggerPrice = fmt.Sprint(ord.TriggerPrice) + param.AlgoPrice = fmt.Sprint(ToFloat64(ord.Price)) + param.Size = fmt.Sprint(ord.Amount) + + reqBody, _, _ := ok.BuildRequestBody(param) + err := ok.DoRequest("POST", PLACE_ALGO_ORDER, reqBody, &response) + + if err != nil { + return ord, err + } + + ord.OrderID2 = response.Data.AlgoId + ord.OrderTime = time.Now().UnixNano() / int64(time.Millisecond) + + return ord, nil +} + +//委托策略撤单 +func (ok *OKExSwap) FutureCancelAlgoOrder(currencyPair CurrencyPair, orderId []string) (bool, error) { + if len(orderId) == 0 { + return false, errors.New("invalid order id") + } + var cancelParam struct { + InstrumentId string `json:"instrument_id"` + AlgoIds []string `json:"algo_ids"` + OrderType string `json:"order_type"` + } + + var resp struct { + ErrorMessage string `json:"error_message"` + ErrorCode string `json:"error_code"` + DetailMsg string `json:"detailMsg"` + Data struct { + Result string `json:"result"` + AlgoIds string `json:"algo_ids"` + InstrumentID string `json:"instrument_id"` + OrderType string `json:"order_type"` + } `json:"data"` + } + + cancelParam.InstrumentId = ok.adaptContractType(currencyPair) + cancelParam.OrderType = "1" + cancelParam.AlgoIds = orderId + + reqBody, _, _ := ok.BuildRequestBody(cancelParam) + + err := ok.DoRequest("POST", CANCEL_ALGO_ORDER, reqBody, &resp) + if err != nil { + return false, err + } + + return resp.Data.Result == "success", nil +} + +//获取委托单列表, status和algo_id必填且只能填其一 +func (ok *OKExSwap) GetFutureAlgoOrders(algo_id string, status string, currencyPair CurrencyPair) ([]FutureOrder, error) { + uri := fmt.Sprintf(GET_ALGO_ORDER, ok.adaptContractType(currencyPair), 1) + if algo_id != "" { + uri += "algo_id=" + algo_id + } else if status != "" { + uri += "status=" + status + } else { + return nil, errors.New("status or algo_id is needed") + } + + var resp struct { + OrderStrategyVOS []struct { + AlgoId string `json:"algo_id"` + AlgoPrice string `json:"algo_price"` + InstrumentId string `json:"instrument_id"` + Leverage string `json:"leverage"` + OrderType string `json:"order_type"` + RealAmount string `json:"real_amount"` + RealPrice string `json:"real_price"` + Size string `json:"size"` + Status string `json:"status"` + Timestamp string `json:"timestamp"` + TriggerPrice string `json:"trigger_price"` + Type string `json:"type"` + } `json:"orderStrategyVOS"` + } + + err := ok.DoRequest("GET", uri, "", &resp) + if err != nil { + return nil, err + } + + var orders []FutureOrder + for _, info := range resp.OrderStrategyVOS { + oTime, _ := time.Parse(time.RFC3339, info.Timestamp) + + ord := FutureOrder{ + OrderID2: info.AlgoId, + Price: ToFloat64(info.AlgoPrice), + Amount: ToFloat64(info.Size), + AvgPrice: ToFloat64(info.RealPrice), + DealAmount: ToFloat64(info.RealAmount), + OrderTime: oTime.UnixNano() / int64(time.Millisecond), + Status: ok.AdaptTradeStatus(ToInt(info.Status)), + Currency: CurrencyPair{}, + OrderType: ToInt(info.OrderType), + OType: ToInt(info.Type), + TriggerPrice: ToFloat64(info.TriggerPrice), + } + ord.Currency = currencyPair + orders = append(orders, ord) + } + + //log.Println(len(orders)) + return orders, nil +} diff --git a/okex/OKExSwap_test.go b/okex/OKExSwap_test.go index d49e3c89..1e412bba 100644 --- a/okex/OKExSwap_test.go +++ b/okex/OKExSwap_test.go @@ -97,3 +97,27 @@ func TestOKExSwap_GetMarginLevel(t *testing.T) { func TestOKExSwap_GetFutureAccountInfo(t *testing.T) { t.Log(okExSwap.GetFutureAccountInfo(goex.BTC_USDT)) } + +func TestOKExSwap_PlaceFutureAlgoOrder(t *testing.T) { + ord := &goex.FutureOrder{ + ContractName: goex.SWAP_CONTRACT, + Currency: goex.BTC_USD, + OType: 2, //开空 + OrderType: 1, //1:止盈止损 2:跟踪委托 3:冰山委托 4:时间加权 + Price: 9877, + Amount: 1, + + TriggerPrice: 9877, + AlgoType: 1, + } + t.Log(okExSwap.PlaceFutureAlgoOrder(ord)) +} + +func TestOKExSwap_FutureCancelAlgoOrder(t *testing.T) { + t.Log(okExSwap.FutureCancelAlgoOrder(goex.BTC_USD, []string{"309935122485305344"})) + +} + +func TestOKExSwap_GetFutureAlgoOrders(t *testing.T) { + t.Log(okExSwap.GetFutureAlgoOrders("", "2", goex.BTC_USD)) +} diff --git a/poloniex/Poloniex.go b/poloniex/Poloniex.go index 441d3755..a2b7200f 100644 --- a/poloniex/Poloniex.go +++ b/poloniex/Poloniex.go @@ -166,11 +166,11 @@ func (poloniex *Poloniex) placeLimitOrder(command, amount, price string, currenc return order, nil } -func (poloniex *Poloniex) LimitBuy(amount, price string, currency CurrencyPair) (*Order, error) { +func (poloniex *Poloniex) LimitBuy(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return poloniex.placeLimitOrder("buy", amount, price, currency) } -func (poloniex *Poloniex) LimitSell(amount, price string, currency CurrencyPair) (*Order, error) { +func (poloniex *Poloniex) LimitSell(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return poloniex.placeLimitOrder("sell", amount, price, currency) } diff --git a/zb/Zb.go b/zb/Zb.go index cd54f043..55d2da85 100644 --- a/zb/Zb.go +++ b/zb/Zb.go @@ -75,7 +75,7 @@ func (zb *Zb) GetDepth(size int, currency CurrencyPair) (*Depth, error) { asks, isok1 := resp["asks"].([]interface{}) bids, isok2 := resp["bids"].([]interface{}) - + if isok2 != true || isok1 != true { return nil, errors.New("no depth data!") } @@ -220,11 +220,11 @@ func (zb *Zb) placeOrder(amount, price string, currency CurrencyPair, tradeType return order, nil } -func (zb *Zb) LimitBuy(amount, price string, currency CurrencyPair) (*Order, error) { +func (zb *Zb) LimitBuy(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return zb.placeOrder(amount, price, currency, 1) } -func (zb *Zb) LimitSell(amount, price string, currency CurrencyPair) (*Order, error) { +func (zb *Zb) LimitSell(amount, price string, currency CurrencyPair, opt ...LimitOrderOptionalParameter) (*Order, error) { return zb.placeOrder(amount, price, currency, 0) }