github.com/nntaoli-project/goex@v1.3.3/okex/OKExSwap.go (about) 1 package okex 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "net/url" 8 "strconv" 9 "strings" 10 "time" 11 12 "github.com/nntaoli-project/goex/internal/logger" 13 14 . "github.com/nntaoli-project/goex" 15 ) 16 17 const ( 18 /* 19 http headers 20 */ 21 OK_ACCESS_KEY = "OK-ACCESS-KEY" 22 OK_ACCESS_SIGN = "OK-ACCESS-SIGN" 23 OK_ACCESS_TIMESTAMP = "OK-ACCESS-TIMESTAMP" 24 OK_ACCESS_PASSPHRASE = "OK-ACCESS-PASSPHRASE" 25 26 /** 27 paging params 28 */ 29 OK_FROM = "OK-FROM" 30 OK_TO = "OK-TO" 31 OK_LIMIT = "OK-LIMIT" 32 33 CONTENT_TYPE = "Content-Type" 34 ACCEPT = "Accept" 35 COOKIE = "Cookie" 36 LOCALE = "locale=" 37 38 APPLICATION_JSON = "application/json" 39 APPLICATION_JSON_UTF8 = "application/json; charset=UTF-8" 40 41 /* 42 i18n: internationalization 43 */ 44 ENGLISH = "en_US" 45 SIMPLIFIED_CHINESE = "zh_CN" 46 //zh_TW || zh_HK 47 TRADITIONAL_CHINESE = "zh_HK" 48 49 /* 50 http methods 51 */ 52 GET = "GET" 53 POST = "POST" 54 DELETE = "DELETE" 55 56 /* 57 others 58 */ 59 ResultDataJsonString = "resultDataJsonString" 60 ResultPageJsonString = "resultPageJsonString" 61 62 BTC_USD_SWAP = "BTC-USD-SWAP" 63 LTC_USD_SWAP = "LTC-USD-SWAP" 64 ETH_USD_SWAP = "ETH-USD-SWAP" 65 ETC_USD_SWAP = "ETC-USD-SWAP" 66 BCH_USD_SWAP = "BCH-USD-SWAP" 67 BSV_USD_SWAP = "BSV-USD-SWAP" 68 EOS_USD_SWAP = "EOS-USD-SWAP" 69 XRP_USD_SWAP = "XRP-USD-SWAP" 70 71 /*Rest Endpoint*/ 72 Endpoint = "https://www.okex.com" 73 GET_ACCOUNTS = "/api/swap/v3/accounts" 74 PLACE_ORDER = "/api/swap/v3/order" 75 CANCEL_ORDER = "/api/swap/v3/cancel_order/%s/%s" 76 GET_ORDER = "/api/swap/v3/orders/%s/%s" 77 GET_POSITION = "/api/swap/v3/%s/position" 78 GET_DEPTH = "/api/swap/v3/instruments/%s/depth?size=%d" 79 GET_TICKER = "/api/swap/v3/instruments/%s/ticker" 80 GET_ALL_TICKER = "/api/swap/v3/instruments/ticker" 81 GET_UNFINISHED_ORDERS = "/api/swap/v3/orders/%s?status=%d&limit=%d" 82 PLACE_ALGO_ORDER = "/api/swap/v3/order_algo" 83 CANCEL_ALGO_ORDER = "/api/swap/v3/cancel_algos" 84 GET_ALGO_ORDER = "/api/swap/v3/order_algo/%s?order_type=%d&" 85 ) 86 87 type BaseResponse struct { 88 ErrorCode string `json:"error_code"` 89 ErrorMessage string `json:"error_message"` 90 Result bool `json:"result,string"` 91 } 92 93 type OKExSwap struct { 94 *OKEx 95 config *APIConfig 96 } 97 98 func NewOKExSwap(config *APIConfig) *OKExSwap { 99 return &OKExSwap{OKEx: &OKEx{config: config}, config: config} 100 } 101 102 func (ok *OKExSwap) GetExchangeName() string { 103 return OKEX_SWAP 104 } 105 106 func (ok *OKExSwap) GetFutureTicker(currencyPair CurrencyPair, contractType string) (*Ticker, error) { 107 var resp struct { 108 InstrumentId string `json:"instrument_id"` 109 Last float64 `json:"last,string"` 110 High24h float64 `json:"high_24h,string"` 111 Low24h float64 `json:"low_24h,string"` 112 BestBid float64 `json:"best_bid,string"` 113 BestAsk float64 `json:"best_ask,string"` 114 Volume24h float64 `json:"volume_24h,string"` 115 Timestamp string `json:"timestamp"` 116 } 117 contractType = ok.adaptContractType(currencyPair) 118 err := ok.DoRequest("GET", fmt.Sprintf(GET_TICKER, contractType), "", &resp) 119 if err != nil { 120 return nil, err 121 } 122 123 date, _ := time.Parse(time.RFC3339, resp.Timestamp) 124 return &Ticker{ 125 Pair: currencyPair, 126 Last: resp.Last, 127 Low: resp.Low24h, 128 High: resp.High24h, 129 Vol: resp.Volume24h, 130 Buy: resp.BestBid, 131 Sell: resp.BestAsk, 132 Date: uint64(date.UnixNano() / int64(time.Millisecond))}, nil 133 } 134 135 func (ok *OKExSwap) GetFutureAllTicker() (*[]FutureTicker, error) { 136 var resp SwapTickerList 137 err := ok.DoRequest("GET", GET_ALL_TICKER, "", &resp) 138 if err != nil { 139 return nil, err 140 } 141 142 var tickers []FutureTicker 143 for _, t := range resp { 144 date, _ := time.Parse(time.RFC3339, t.Timestamp) 145 tickers = append(tickers, FutureTicker{ 146 ContractType: t.InstrumentId, 147 Ticker: &Ticker{ 148 Pair: NewCurrencyPair3(t.InstrumentId, "-"), 149 Sell: t.BestAsk, 150 Buy: t.BestBid, 151 Low: t.Low24h, 152 High: t.High24h, 153 Last: t.Last, 154 Vol: t.Volume24h, 155 Date: uint64(date.UnixNano() / int64(time.Millisecond))}}) 156 } 157 158 return &tickers, nil 159 } 160 161 func (ok *OKExSwap) GetFutureDepth(currencyPair CurrencyPair, contractType string, size int) (*Depth, error) { 162 var resp SwapInstrumentDepth 163 contractType = ok.adaptContractType(currencyPair) 164 165 err := ok.DoRequest("GET", fmt.Sprintf(GET_DEPTH, contractType, size), "", &resp) 166 if err != nil { 167 return nil, err 168 } 169 170 var dep Depth 171 dep.ContractType = contractType 172 dep.Pair = currencyPair 173 dep.UTime, _ = time.Parse(time.RFC3339, resp.Timestamp) 174 175 for _, v := range resp.Bids { 176 dep.BidList = append(dep.BidList, DepthRecord{ 177 Price: ToFloat64(v[0]), 178 Amount: ToFloat64(v[1])}) 179 } 180 181 for i := len(resp.Asks) - 1; i >= 0; i-- { 182 dep.AskList = append(dep.AskList, DepthRecord{ 183 Price: ToFloat64(resp.Asks[i][0]), 184 Amount: ToFloat64(resp.Asks[i][1])}) 185 } 186 187 return &dep, nil 188 } 189 190 func (ok *OKExSwap) GetFutureUserinfo(currencyPair ...CurrencyPair) (*FutureAccount, error) { 191 var ( 192 err error 193 infos SwapAccounts 194 ) 195 196 if len(currencyPair) == 1 { 197 accountInfo, err := ok.GetFutureAccountInfo(currencyPair[0]) 198 if err != nil { 199 return nil, err 200 } 201 202 if accountInfo == nil { 203 return nil, errors.New("api return info is empty") 204 } 205 206 infos.Info = append(infos.Info, *accountInfo) 207 208 goto wrapperF 209 } 210 211 err = ok.OKEx.DoRequest("GET", GET_ACCOUNTS, "", &infos) 212 if err != nil { 213 return nil, err 214 } 215 216 //log.Println(infos) 217 wrapperF: 218 acc := FutureAccount{} 219 acc.FutureSubAccounts = make(map[Currency]FutureSubAccount, 2) 220 221 for _, account := range infos.Info { 222 subAcc := FutureSubAccount{AccountRights: account.Equity, 223 KeepDeposit: account.Margin, ProfitReal: account.RealizedPnl, 224 ProfitUnreal: account.UnrealizedPnl, RiskRate: account.MarginRatio} 225 meta := strings.Split(account.InstrumentId, "-") 226 if len(meta) > 0 { 227 subAcc.Currency = NewCurrency(meta[0], "") 228 } 229 acc.FutureSubAccounts[subAcc.Currency] = subAcc 230 } 231 232 return &acc, nil 233 } 234 235 func (ok *OKExSwap) GetFutureAccountInfo(currency CurrencyPair) (*SwapAccountInfo, error) { 236 var infos struct { 237 Info SwapAccountInfo `json:"info"` 238 } 239 240 err := ok.OKEx.DoRequest("GET", fmt.Sprintf("/api/swap/v3/%s/accounts", ok.adaptContractType(currency)), "", &infos) 241 if err != nil { 242 return nil, err 243 } 244 245 return &infos.Info, nil 246 } 247 248 /* 249 OKEX swap api parameter's definition 250 @author Lingting Fu 251 @date 2018-12-27 252 @version 1.0.0 253 */ 254 255 type BasePlaceOrderInfo struct { 256 ClientOid string `json:"client_oid"` 257 Price string `json:"price"` 258 MatchPrice string `json:"match_price"` 259 Type string `json:"type"` 260 Size string `json:"size"` 261 OrderType string `json:"order_type"` 262 } 263 264 type PlaceOrderInfo struct { 265 BasePlaceOrderInfo 266 InstrumentId string `json:"instrument_id"` 267 } 268 269 type PlaceOrdersInfo struct { 270 InstrumentId string `json:"instrument_id"` 271 OrderData []*BasePlaceOrderInfo `json:"order_data"` 272 } 273 274 func (ok *OKExSwap) PlaceFutureOrder(currencyPair CurrencyPair, contractType, price, amount string, openType, matchPrice int, leverRate float64) (string, error) { 275 fOrder, err := ok.PlaceFutureOrder2(currencyPair, contractType, price, amount, openType, matchPrice) 276 return fOrder.OrderID2, err 277 } 278 279 func (ok *OKExSwap) PlaceFutureOrder2(currencyPair CurrencyPair, contractType, price, amount string, openType, matchPrice int, opt ...LimitOrderOptionalParameter) (*FutureOrder, error) { 280 cid := GenerateOrderClientId(32) 281 param := PlaceOrderInfo{ 282 BasePlaceOrderInfo{ 283 ClientOid: cid, 284 Price: price, 285 MatchPrice: fmt.Sprint(matchPrice), 286 Type: fmt.Sprint(openType), 287 Size: amount, 288 OrderType: "0", 289 }, 290 ok.adaptContractType(currencyPair), 291 } 292 293 if len(opt) > 0 { 294 switch opt[0] { 295 case PostOnly: 296 param.OrderType = "1" 297 case Fok: 298 param.OrderType = "2" 299 case Ioc: 300 param.OrderType = "3" 301 } 302 } 303 304 reqBody, _, _ := ok.OKEx.BuildRequestBody(param) 305 306 fOrder := &FutureOrder{ 307 ClientOid: cid, 308 Currency: currencyPair, 309 ContractName: contractType, 310 OType: openType, 311 Price: ToFloat64(price), 312 Amount: ToFloat64(amount), 313 } 314 315 var resp struct { 316 BaseResponse 317 OrderID string `json:"order_id"` 318 ClientOid string `json:"client_oid"` 319 } 320 321 err := ok.DoRequest("POST", PLACE_ORDER, reqBody, &resp) 322 if err != nil { 323 logger.Errorf("[param] %s", param) 324 return fOrder, err 325 } 326 327 if resp.ErrorMessage != "" { 328 logger.Errorf("[param] %s", param) 329 return fOrder, errors.New(fmt.Sprintf("%s:%s", resp.ErrorCode, resp.ErrorMessage)) 330 } 331 332 fOrder.OrderID2 = resp.OrderID 333 334 return fOrder, nil 335 } 336 337 func (ok *OKExSwap) LimitFuturesOrder(currencyPair CurrencyPair, contractType, price, amount string, openType int, opt ...LimitOrderOptionalParameter) (*FutureOrder, error) { 338 return ok.PlaceFutureOrder2(currencyPair, contractType, price, amount, openType, 0, opt...) 339 } 340 341 func (ok *OKExSwap) MarketFuturesOrder(currencyPair CurrencyPair, contractType, amount string, openType int) (*FutureOrder, error) { 342 return ok.PlaceFutureOrder2(currencyPair, contractType, "0", amount, openType, 1) 343 } 344 345 func (ok *OKExSwap) FutureCancelOrder(currencyPair CurrencyPair, contractType, orderId string) (bool, error) { 346 var cancelParam struct { 347 OrderId string `json:"order_id"` 348 InstrumentId string `json:"instrument_id"` 349 } 350 351 var resp SwapCancelOrderResult 352 353 cancelParam.InstrumentId = contractType 354 cancelParam.OrderId = orderId 355 356 //req, _, _ := BuildRequestBody(cancelParam) 357 358 err := ok.DoRequest("POST", fmt.Sprintf(CANCEL_ORDER, ok.adaptContractType(currencyPair), orderId), "", &resp) 359 if err != nil { 360 return false, err 361 } 362 363 return resp.Result, nil 364 } 365 366 func (ok *OKExSwap) GetFutureOrderHistory(pair CurrencyPair, contractType string, optional ...OptionalParameter) ([]FutureOrder, error) { 367 urlPath := fmt.Sprintf("/api/swap/v3/orders/%s?", ok.adaptContractType(pair)) 368 369 param := url.Values{} 370 param.Set("limit", "100") 371 param.Set("state", "7") 372 MergeOptionalParameter(¶m, optional...) 373 374 var response SwapOrdersInfo 375 376 err := ok.DoRequest("GET", urlPath+param.Encode(), "", &response) 377 if err != nil { 378 return nil, err 379 } 380 381 orders := make([]FutureOrder, 0, 100) 382 for _, info := range response.OrderInfo { 383 ord := ok.parseOrder(info) 384 ord.Currency = pair 385 ord.ContractName = contractType 386 orders = append(orders, ord) 387 } 388 389 return orders, nil 390 } 391 392 func (ok *OKExSwap) parseOrder(ord BaseOrderInfo) FutureOrder { 393 oTime, _ := time.Parse(time.RFC3339, ord.Timestamp) 394 return FutureOrder{ 395 ClientOid: ord.ClientOid, 396 OrderID2: ord.OrderId, 397 Amount: ord.Size, 398 Price: ord.Price, 399 DealAmount: ord.FilledQty, 400 AvgPrice: ord.PriceAvg, 401 OType: ord.Type, 402 Status: ok.AdaptTradeStatus(ord.Status), 403 Fee: ord.Fee, 404 OrderTime: oTime.UnixNano() / int64(time.Millisecond)} 405 } 406 407 func (ok *OKExSwap) GetUnfinishFutureOrders(currencyPair CurrencyPair, contractType string) ([]FutureOrder, error) { 408 var ( 409 resp SwapOrdersInfo 410 ) 411 contractType = ok.adaptContractType(currencyPair) 412 err := ok.DoRequest("GET", fmt.Sprintf(GET_UNFINISHED_ORDERS, contractType, 6, 100), "", &resp) 413 if err != nil { 414 return nil, err 415 } 416 417 if resp.Message != "" { 418 return nil, errors.New(fmt.Sprintf("{\"ErrCode\":%d,\"ErrMessage\":\"%s\"", resp.Code, resp.Message)) 419 } 420 421 var orders []FutureOrder 422 for _, info := range resp.OrderInfo { 423 ord := ok.parseOrder(info) 424 ord.Currency = currencyPair 425 ord.ContractName = contractType 426 orders = append(orders, ord) 427 } 428 429 //log.Println(len(orders)) 430 return orders, nil 431 } 432 433 /** 434 *获取订单信息 435 */ 436 func (ok *OKExSwap) GetFutureOrders(orderIds []string, currencyPair CurrencyPair, contractType string) ([]FutureOrder, error) { 437 panic("") 438 } 439 440 /** 441 *获取单个订单信息 442 */ 443 func (ok *OKExSwap) GetFutureOrder(orderId string, currencyPair CurrencyPair, contractType string) (*FutureOrder, error) { 444 var getOrderParam struct { 445 OrderId string `json:"order_id"` 446 InstrumentId string `json:"instrument_id"` 447 } 448 449 var resp struct { 450 BizWarmTips 451 BaseOrderInfo 452 } 453 454 contractType = ok.adaptContractType(currencyPair) 455 456 getOrderParam.OrderId = orderId 457 getOrderParam.InstrumentId = contractType 458 459 //reqBody, _, _ := BuildRequestBody(getOrderParam) 460 461 err := ok.DoRequest("GET", fmt.Sprintf(GET_ORDER, contractType, orderId), "", &resp) 462 if err != nil { 463 return nil, err 464 } 465 466 if resp.Message != "" { 467 return nil, errors.New(fmt.Sprintf("{\"ErrCode\":%d,\"ErrMessage\":\"%s\"}", resp.Code, resp.Message)) 468 } 469 470 oTime, err := time.Parse(time.RFC3339, resp.Timestamp) 471 472 return &FutureOrder{ 473 ClientOid: resp.ClientOid, 474 Currency: currencyPair, 475 ContractName: contractType, 476 OrderID2: resp.OrderId, 477 Amount: resp.Size, 478 Price: resp.Price, 479 DealAmount: resp.FilledQty, 480 AvgPrice: resp.PriceAvg, 481 OType: resp.Type, 482 Fee: resp.Fee, 483 Status: ok.AdaptTradeStatus(resp.Status), 484 OrderTime: oTime.UnixNano() / int64(time.Millisecond), 485 }, nil 486 } 487 488 func (ok *OKExSwap) GetFuturePosition(currencyPair CurrencyPair, contractType string) ([]FuturePosition, error) { 489 var resp SwapPosition 490 contractType = ok.adaptContractType(currencyPair) 491 492 err := ok.DoRequest("GET", fmt.Sprintf(GET_POSITION, contractType), "", &resp) 493 if err != nil { 494 return nil, err 495 } 496 497 var positions []FuturePosition 498 499 positions = append(positions, FuturePosition{ 500 ContractType: contractType, 501 Symbol: currencyPair}) 502 503 var ( 504 buyPosition SwapPositionHolding 505 sellPosition SwapPositionHolding 506 ) 507 508 if len(resp.Holding) > 0 { 509 if resp.Holding[0].Side == "long" { 510 buyPosition = resp.Holding[0] 511 if len(resp.Holding) == 2 { 512 sellPosition = resp.Holding[1] 513 } 514 } else { 515 sellPosition = resp.Holding[0] 516 if len(resp.Holding) == 2 { 517 buyPosition = resp.Holding[1] 518 } 519 } 520 521 positions[0].ForceLiquPrice = buyPosition.LiquidationPrice 522 positions[0].BuyAmount = buyPosition.Position 523 positions[0].BuyAvailable = buyPosition.AvailPosition 524 positions[0].BuyPriceAvg = buyPosition.AvgCost 525 positions[0].BuyProfitReal = buyPosition.RealizedPnl 526 positions[0].BuyPriceCost = buyPosition.SettlementPrice 527 528 positions[0].ForceLiquPrice = sellPosition.LiquidationPrice 529 positions[0].SellAmount = sellPosition.Position 530 positions[0].SellAvailable = sellPosition.AvailPosition 531 positions[0].SellPriceAvg = sellPosition.AvgCost 532 positions[0].SellProfitReal = sellPosition.RealizedPnl 533 positions[0].SellPriceCost = sellPosition.SettlementPrice 534 535 positions[0].LeverRate = ToFloat64(sellPosition.Leverage) 536 } 537 return positions, nil 538 } 539 540 /** 541 * BTC: 100美元一张合约 542 * LTC/ETH/ETC/BCH: 10美元一张合约 543 */ 544 func (ok *OKExSwap) GetContractValue(currencyPair CurrencyPair) (float64, error) { 545 if currencyPair.CurrencyA.Eq(BTC) { 546 return 100, nil 547 } 548 return 10, nil 549 } 550 551 func (ok *OKExSwap) GetFee() (float64, error) { 552 panic("not support") 553 } 554 555 func (ok *OKExSwap) GetFutureEstimatedPrice(currencyPair CurrencyPair) (float64, error) { 556 panic("not support") 557 } 558 559 func (ok *OKExSwap) GetFutureIndex(currencyPair CurrencyPair) (float64, error) { 560 panic("not support") 561 } 562 563 func (ok *OKExSwap) GetDeliveryTime() (int, int, int, int) { 564 panic("not support") 565 } 566 567 func (ok *OKExSwap) GetKlineRecords(contractType string, currency CurrencyPair, period KlinePeriod, size int, opt ...OptionalParameter) ([]FutureKline, error) { 568 granularity := adaptKLinePeriod(KlinePeriod(period)) 569 if granularity == -1 { 570 return nil, errors.New("kline period parameter is error") 571 } 572 return ok.GetKlineRecords2(contractType, currency, "", "", strconv.Itoa(granularity)) 573 } 574 575 /** 576 since : 单位秒,开始时间 577 to : 单位秒,结束时间 578 */ 579 func (ok *OKExSwap) GetKlineRecordsByRange(currency CurrencyPair, period, since, to int) ([]FutureKline, error) { 580 urlPath := "/api/swap/v3/instruments/%s/candles?start=%s&end=%s&granularity=%d" 581 sinceTime := time.Unix(int64(since), 0).UTC().Format(time.RFC3339) 582 toTime := time.Unix(int64(to), 0).UTC().Format(time.RFC3339) 583 contractId := ok.adaptContractType(currency) 584 granularity := adaptKLinePeriod(KlinePeriod(period)) 585 if granularity == -1 { 586 return nil, errors.New("kline period parameter is error") 587 } 588 589 var response [][]interface{} 590 err := ok.DoRequest("GET", fmt.Sprintf(urlPath, contractId, sinceTime, toTime, granularity), "", &response) 591 if err != nil { 592 return nil, err 593 } 594 595 var klines []FutureKline 596 for _, itm := range response { 597 t, _ := time.Parse(time.RFC3339, fmt.Sprint(itm[0])) 598 klines = append(klines, FutureKline{ 599 Kline: &Kline{ 600 Timestamp: t.Unix(), 601 Pair: currency, 602 Open: ToFloat64(itm[1]), 603 High: ToFloat64(itm[2]), 604 Low: ToFloat64(itm[3]), 605 Close: ToFloat64(itm[4]), 606 Vol: ToFloat64(itm[5])}, 607 Vol2: ToFloat64(itm[6])}) 608 } 609 610 return klines, nil 611 } 612 613 /** 614 since : 单位秒,开始时间 615 */ 616 func (ok *OKExSwap) GetKlineRecords2(contractType string, currency CurrencyPair, start, end, period string) ([]FutureKline, error) { 617 urlPath := "/api/swap/v3/instruments/%s/candles?%s" 618 params := url.Values{} 619 if start != "" { 620 params.Set("start", start) 621 } 622 if end != "" { 623 params.Set("end", end) 624 } 625 if period != "" { 626 params.Set("granularity", period) 627 } 628 contractId := ok.adaptContractType(currency) 629 630 var response [][]interface{} 631 err := ok.DoRequest("GET", fmt.Sprintf(urlPath, contractId, params.Encode()), "", &response) 632 if err != nil { 633 return nil, err 634 } 635 636 var kline []FutureKline 637 for _, itm := range response { 638 t, _ := time.Parse(time.RFC3339, fmt.Sprint(itm[0])) 639 kline = append(kline, FutureKline{ 640 Kline: &Kline{ 641 Timestamp: t.Unix(), 642 Pair: currency, 643 Open: ToFloat64(itm[1]), 644 High: ToFloat64(itm[2]), 645 Low: ToFloat64(itm[3]), 646 Close: ToFloat64(itm[4]), 647 Vol: ToFloat64(itm[5])}, 648 Vol2: ToFloat64(itm[6])}) 649 } 650 651 return kline, nil 652 } 653 654 func (ok *OKExSwap) GetTrades(contractType string, currencyPair CurrencyPair, since int64) ([]Trade, error) { 655 panic("not support") 656 } 657 658 func (ok *OKExSwap) GetExchangeRate() (float64, error) { 659 panic("not support") 660 } 661 662 func (ok *OKExSwap) GetHistoricalFunding(contractType string, currencyPair CurrencyPair, page int) ([]HistoricalFunding, error) { 663 var resp []HistoricalFunding 664 uri := fmt.Sprintf("/api/swap/v3/instruments/%s/historical_funding_rate?from=%d", ok.adaptContractType(currencyPair), page) 665 err := ok.DoRequest("GET", uri, "", &resp) 666 if err != nil { 667 return nil, err 668 } 669 return resp, nil 670 } 671 672 func (ok *OKExSwap) AdaptTradeStatus(status int) TradeStatus { 673 switch status { 674 case -1: 675 return ORDER_CANCEL 676 case 0: 677 return ORDER_UNFINISH 678 case 1: 679 return ORDER_PART_FINISH 680 case 2: 681 return ORDER_FINISH 682 default: 683 return ORDER_UNFINISH 684 } 685 } 686 687 func (ok *OKExSwap) adaptContractType(currencyPair CurrencyPair) string { 688 return fmt.Sprintf("%s-SWAP", currencyPair.ToSymbol("-")) 689 } 690 691 type Instrument struct { 692 InstrumentID string `json:"instrument_id"` 693 UnderlyingIndex string `json:"underlying_index"` 694 QuoteCurrency string `json:"quote_currency"` 695 Coin string `json:"coin"` 696 ContractVal float64 `json:"contract_val,string"` 697 Listing time.Time `json:"listing"` 698 Delivery time.Time `json:"delivery"` 699 SizeIncrement int `json:"size_increment,string"` 700 TickSize float64 `json:"tick_size,string"` 701 BaseCurrency string `json:"base_currency"` 702 Underlying string `json:"underlying"` 703 SettlementCurrency string `json:"settlement_currency"` 704 IsInverse bool `json:"is_inverse,string"` 705 ContractValCurrency string `json:"contract_val_currency"` 706 } 707 708 func (ok *OKExSwap) GetInstruments() ([]Instrument, error) { 709 var resp []Instrument 710 err := ok.DoRequest("GET", "/api/swap/v3/instruments", "", &resp) 711 if err != nil { 712 return nil, err 713 } 714 return resp, nil 715 } 716 717 type MarginLeverage struct { 718 LongLeverage float64 `json:"long_leverage,string"` 719 MarginMode string `json:"margin_mode"` 720 ShortLeverage float64 `json:"short_leverage,string"` 721 InstrumentId string `json:"instrument_id"` 722 } 723 724 func (ok *OKExSwap) GetMarginLevel(currencyPair CurrencyPair) (*MarginLeverage, error) { 725 var resp MarginLeverage 726 uri := fmt.Sprintf("/api/swap/v3/accounts/%s/settings", ok.adaptContractType(currencyPair)) 727 728 err := ok.DoRequest("GET", uri, "", &resp) 729 if err != nil { 730 return nil, err 731 } 732 return &resp, nil 733 734 } 735 736 // marginmode 737 //1:逐仓-多仓 738 //2:逐仓-空仓 739 //3:全仓 740 func (ok *OKExSwap) SetMarginLevel(currencyPair CurrencyPair, level, marginMode int) (*MarginLeverage, error) { 741 var resp MarginLeverage 742 uri := fmt.Sprintf("/api/swap/v3/accounts/%s/leverage", ok.adaptContractType(currencyPair)) 743 744 reqBody := make(map[string]string) 745 reqBody["leverage"] = strconv.Itoa(level) 746 reqBody["side"] = strconv.Itoa(marginMode) 747 data, err := json.Marshal(reqBody) 748 if err != nil { 749 return nil, err 750 } 751 752 err = ok.DoRequest("POST", uri, string(data), &resp) 753 if err != nil { 754 return nil, err 755 } 756 return &resp, nil 757 } 758 759 //委托策略下单 algo_type 1:限价 2:市场价;触发价格类型,默认是限价;为市场价时,委托价格不必填; 760 func (ok *OKExSwap) PlaceFutureAlgoOrder(ord *FutureOrder) (*FutureOrder, error) { 761 var param struct { 762 InstrumentId string `json:"instrument_id"` 763 Type int `json:"type"` 764 OrderType int `json:"order_type"` //1:止盈止损 2:跟踪委托 3:冰山委托 4:时间加权 765 Size string `json:"size"` 766 TriggerPrice string `json:"trigger_price"` 767 AlgoPrice string `json:"algo_price"` 768 AlgoType string `json:"algo_type"` 769 } 770 771 var response struct { 772 ErrorMessage string `json:"error_message"` 773 ErrorCode string `json:"error_code"` 774 DetailMsg string `json:"detail_msg"` 775 776 Data struct { 777 Result string `json:"result"` 778 ErrorMessage string `json:"error_message"` 779 ErrorCode string `json:"error_code"` 780 AlgoId string `json:"algo_id"` 781 InstrumentId string `json:"instrument_id"` 782 OrderType int `json:"order_type"` 783 } `json:"data"` 784 } 785 if ord == nil { 786 return nil, errors.New("ord param is nil") 787 } 788 param.InstrumentId = ok.adaptContractType(ord.Currency) 789 param.Type = ord.OType 790 param.OrderType = ord.OrderType 791 param.AlgoType = fmt.Sprint(ord.AlgoType) 792 param.TriggerPrice = fmt.Sprint(ord.TriggerPrice) 793 param.AlgoPrice = fmt.Sprint(ToFloat64(ord.Price)) 794 param.Size = fmt.Sprint(ord.Amount) 795 796 reqBody, _, _ := ok.BuildRequestBody(param) 797 err := ok.DoRequest("POST", PLACE_ALGO_ORDER, reqBody, &response) 798 799 if err != nil { 800 return ord, err 801 } 802 803 ord.OrderID2 = response.Data.AlgoId 804 ord.OrderTime = time.Now().UnixNano() / int64(time.Millisecond) 805 806 return ord, nil 807 } 808 809 //委托策略撤单 810 func (ok *OKExSwap) FutureCancelAlgoOrder(currencyPair CurrencyPair, orderId []string) (bool, error) { 811 if len(orderId) == 0 { 812 return false, errors.New("invalid order id") 813 } 814 var cancelParam struct { 815 InstrumentId string `json:"instrument_id"` 816 AlgoIds []string `json:"algo_ids"` 817 OrderType string `json:"order_type"` 818 } 819 820 var resp struct { 821 ErrorMessage string `json:"error_message"` 822 ErrorCode string `json:"error_code"` 823 DetailMsg string `json:"detailMsg"` 824 Data struct { 825 Result string `json:"result"` 826 AlgoIds string `json:"algo_ids"` 827 InstrumentID string `json:"instrument_id"` 828 OrderType string `json:"order_type"` 829 } `json:"data"` 830 } 831 832 cancelParam.InstrumentId = ok.adaptContractType(currencyPair) 833 cancelParam.OrderType = "1" 834 cancelParam.AlgoIds = orderId 835 836 reqBody, _, _ := ok.BuildRequestBody(cancelParam) 837 838 err := ok.DoRequest("POST", CANCEL_ALGO_ORDER, reqBody, &resp) 839 if err != nil { 840 return false, err 841 } 842 843 return resp.Data.Result == "success", nil 844 } 845 846 //获取委托单列表, status和algo_id必填且只能填其一 847 func (ok *OKExSwap) GetFutureAlgoOrders(algo_id string, status string, currencyPair CurrencyPair) ([]FutureOrder, error) { 848 uri := fmt.Sprintf(GET_ALGO_ORDER, ok.adaptContractType(currencyPair), 1) 849 if algo_id != "" { 850 uri += "algo_id=" + algo_id 851 } else if status != "" { 852 uri += "status=" + status 853 } else { 854 return nil, errors.New("status or algo_id is needed") 855 } 856 857 var resp struct { 858 OrderStrategyVOS []struct { 859 AlgoId string `json:"algo_id"` 860 AlgoPrice string `json:"algo_price"` 861 InstrumentId string `json:"instrument_id"` 862 Leverage string `json:"leverage"` 863 OrderType string `json:"order_type"` 864 RealAmount string `json:"real_amount"` 865 RealPrice string `json:"real_price"` 866 Size string `json:"size"` 867 Status string `json:"status"` 868 Timestamp string `json:"timestamp"` 869 TriggerPrice string `json:"trigger_price"` 870 Type string `json:"type"` 871 } `json:"orderStrategyVOS"` 872 } 873 874 err := ok.DoRequest("GET", uri, "", &resp) 875 if err != nil { 876 return nil, err 877 } 878 879 var orders []FutureOrder 880 for _, info := range resp.OrderStrategyVOS { 881 oTime, _ := time.Parse(time.RFC3339, info.Timestamp) 882 883 ord := FutureOrder{ 884 OrderID2: info.AlgoId, 885 Price: ToFloat64(info.AlgoPrice), 886 Amount: ToFloat64(info.Size), 887 AvgPrice: ToFloat64(info.RealPrice), 888 DealAmount: ToFloat64(info.RealAmount), 889 OrderTime: oTime.UnixNano() / int64(time.Millisecond), 890 Status: ok.AdaptTradeStatus(ToInt(info.Status)), 891 Currency: CurrencyPair{}, 892 OrderType: ToInt(info.OrderType), 893 OType: ToInt(info.Type), 894 TriggerPrice: ToFloat64(info.TriggerPrice), 895 } 896 ord.Currency = currencyPair 897 orders = append(orders, ord) 898 } 899 900 //log.Println(len(orders)) 901 return orders, nil 902 }