exchanges/ftx: Order improvements: submission + websocket reports (#741)

* exchanges/ftx: add support for ReduceOnly, ImmediateOrCancel and PostOnly orders

* exchanges/ftx: adapt tests to ReduceOnly/ImmediateOrCancel/PostOnly boolean flags

* exchanges/ftx: wrong json key of WsFillsDataStore.FillsData was causing json.Unmarshal() to yield an empty struct

* exchanges/ftx: update WsFills to latest API

* exchanges/ftx: add TestFTX_wsHandleData_wsFills

* exchanges/ftx: WsOrders.FilledSize was never parsed properly because of a key error (was spelled `filedSize` -- with one L);  enrich data structure to support latest API fields

* exchanges/ftx: when order is closed, set status to closed, not canceled

* exchanges/ftx: compatibleOrderVars: compare floats for almost-equality

* order.Detail: add field: AverageExecutedPrice float64

* exchanges/ftx: FTX.wsHandleData() now populates all order.Detail fields properly on update/orders websocket message

* exchanges/ftx: implement TestFTX_wsHandleData_Details()

* exchanges/ftx: make golangci-lint happy

* exchanges/ftx: make golangci-lint happy

* exchanges/ftx/test: delete redundant commented code

* exchanges/ftx: move websocket tests from ftx_test.go to ftx_websocket_test.go

* exchanges/ftx: remove redundant line

* exchange/ftx: greatly simplify TestFTX_wsHandleData (thanks to @shazbert)

* exchanges/ftx: make golangci-lint/whitespace happy

* exchanges/ftx: requested review change: delete a redundant line

* exchanges/ftx/test: use predefined currency constants
This commit is contained in:
Yordan Miladinov
2021-08-11 03:28:47 +03:00
committed by GitHub
parent 232d6ebc1f
commit c7c8cac21f
7 changed files with 477 additions and 297 deletions

View File

@@ -7,6 +7,7 @@ import (
"errors"
"fmt"
"io"
"math"
"net/http"
"net/url"
"strconv"
@@ -659,20 +660,25 @@ func (f *FTX) GetTriggerOrderHistory(marketName string, startTime, endTime time.
}
// Order places an order
func (f *FTX) Order(marketName, side, orderType, reduceOnly, ioc, postOnly, clientID string, price, size float64) (OrderData, error) {
func (f *FTX) Order(
marketName, side, orderType string,
reduceOnly, ioc, postOnly bool,
clientID string,
price, size float64,
) (OrderData, error) {
req := make(map[string]interface{})
req["market"] = marketName
req["side"] = side
req["price"] = price
req["type"] = orderType
req["size"] = size
if reduceOnly != "" {
if reduceOnly {
req["reduceOnly"] = reduceOnly
}
if ioc != "" {
if ioc {
req["ioc"] = ioc
}
if postOnly != "" {
if postOnly {
req["postOnly"] = postOnly
}
if clientID != "" {
@@ -1235,15 +1241,19 @@ func (f *FTX) compatibleOrderVars(orderSide, orderStatus, orderType string, amou
case strings.ToLower(order.Open.String()):
resp.Status = order.Open
case closedStatus:
if filledAmount != 0 && filledAmount != amount {
resp.Status = order.PartiallyCancelled
break
}
if filledAmount == 0 {
switch {
case filledAmount <= 0:
// Order is closed with a filled amount of 0, which means it's
// cancelled.
resp.Status = order.Cancelled
break
}
if filledAmount == amount {
case math.Abs(filledAmount-amount) > 1e-6:
// Order is closed with filledAmount above 0, but not equal to the
// full amount, which means it's partially executed and then
// cancelled.
resp.Status = order.PartiallyCancelled
default:
// Order is closed and filledAmount == amount, which means it's
// fully executed.
resp.Status = order.Filled
}
default:

View File

@@ -540,7 +540,7 @@ func TestOrder(t *testing.T) {
if !areTestAPIKeysSet() || !canManipulateRealOrders {
t.Skip("skipping test, either api keys or canManipulateRealOrders isnt set correctly")
}
_, err := f.Order(spotPair, order.Buy.Lower(), "limit", "", "", "", "", 0.0001, 500)
_, err := f.Order(spotPair, order.Buy.Lower(), "limit", false, false, false, "", 0.0001, 500)
if err != nil {
t.Error(err)
}
@@ -1149,183 +1149,6 @@ func TestGetHistoricCandlesExtended(t *testing.T) {
}
}
func TestParsingWSFillData(t *testing.T) {
t.Parallel()
data := []byte(`{
"channel": "fills",
"data": {
"fee": 78.05799225,
"feeRate": 0.0014,
"future": "BTC-PERP",
"id": 7828307,
"liquidity": "taker",
"market": "BTC-PERP",
"orderId": 38065410,
"tradeId": 19129310,
"price": 3723.75,
"side": "buy",
"size": 14.973,
"time": "2019-05-07T16:40:58.358438+00:00",
"type": "order"
},
"type": "update"
}`)
err := f.wsHandleData(data)
if err != nil {
t.Error(err)
}
}
func TestParsingOrders(t *testing.T) {
t.Parallel()
data := []byte(`{
"channel": "fills",
"data": {
"id": 24852229,
"clientId": null,
"market": "XRP-PERP",
"type": "limit",
"side": "buy",
"size": 42353.0,
"price": 0.2977,
"reduceOnly": false,
"ioc": false,
"postOnly": false,
"status": "closed",
"filledSize": 0.0,
"remainingSize": 0.0,
"avgFillPrice": 0.2978
},
"type": "update"
}`)
err := f.wsHandleData(data)
if err != nil {
t.Error(err)
}
}
func TestParsingWSTradesData(t *testing.T) {
t.Parallel()
data := []byte(`{
"channel": "trades",
"market": "BTC-PERP",
"type": "update",
"data": [
{
"id": 44200173,
"price": 9761.0,
"size": 0.0008,
"side": "buy",
"liquidation": false,
"time": "2020-05-15T01:10:04.369194+00:00"
}
]
}`)
err := f.wsHandleData(data)
if err != nil {
t.Error(err)
}
}
func TestParsingWSTickerData(t *testing.T) {
t.Parallel()
data := []byte(`{
"channel": "ticker",
"market": "BTC-PERP",
"type": "update",
"data": {
"bid": 9760.5,
"ask": 9761.0,
"bidSize": 3.36,
"askSize": 71.8484,
"last": 9761.0,
"time": 1589505004.4237103
}
}`)
err := f.wsHandleData(data)
if err != nil {
t.Error(err)
}
}
func TestParsingWSOrdersData(t *testing.T) {
t.Parallel()
data := []byte(`{
"channel": "orders",
"data": {
"id": 24852229,
"clientId": null,
"market": "BTC-PERP",
"type": "limit",
"side": "buy",
"size": 42353.0,
"price": 0.2977,
"reduceOnly": false,
"ioc": false,
"postOnly": false,
"status": "closed",
"filledSize": 0.0,
"remainingSize": 0.0,
"avgFillPrice": 0.2978
},
"type": "update"
}`)
err := f.wsHandleData(data)
if err != nil {
t.Error(err)
}
}
func TestParsingMarketsData(t *testing.T) {
t.Parallel()
data := []byte(`{"channel": "markets",
"type": "partial",
"data": {
"ADA-0626": {
"name": "ADA-0626",
"enabled": true,
"priceIncrement": 5e-06,
"sizeIncrement": 1.0,
"type": "future",
"baseCurrency": null,
"quoteCurrency": null,
"restricted": false,
"underlying": "ADA",
"future": {
"name": "ADA-0626",
"underlying": "ADA",
"description": "Cardano June 2020 Futures",
"type": "future", "expiry": "2020-06-26T003:00:00+00:00",
"perpetual": false,
"expired": false,
"enabled": true,
"postOnly": false,
"imfFactor": 4e-05,
"underlyingDescription": "Cardano",
"expiryDescription": "June 2020",
"moveStart": null, "positionLimitWeight": 10.0,
"group": "quarterly"}}},
"action": "partial"
}`)
err := f.wsHandleData(data)
if err != nil {
t.Error(err)
}
}
func TestParsingWSOBData(t *testing.T) {
data := []byte(`{"channel": "orderbook", "market": "BTC-PERP", "type": "partial", "data": {"time": 1589855831.4606245, "checksum": 225973019, "bids": [[9602.0, 3.2903], [9601.5, 3.11], [9601.0, 2.1356], [9600.5, 3.0991], [9600.0, 8.014], [9599.5, 4.1571], [9599.0, 79.1846], [9598.5, 3.099], [9598.0, 3.985], [9597.5, 3.999], [9597.0, 16.4335], [9596.5, 4.006], [9596.0, 3.2596], [9595.0, 6.334], [9594.0, 3.5685], [9593.0, 14.2717], [9592.5, 0.5], [9591.0, 2.181], [9590.5, 40.4246], [9590.0, 1.0], [9589.0, 1.357], [9588.5, 0.4738], [9587.5, 0.15], [9587.0, 16.811], [9586.5, 1.2], [9586.0, 0.2], [9585.5, 1.0], [9584.5, 0.002], [9584.0, 1.51], [9583.5, 0.01], [9583.0, 1.4], [9582.5, 0.1], [9582.0, 24.7921], [9581.0, 2.087], [9580.5, 2.0], [9580.0, 0.1], [9579.0, 1.1588], [9578.0, 0.9477], [9577.5, 22.216], [9576.0, 0.2], [9574.0, 22.0], [9573.5, 1.0], [9572.0, 0.203], [9570.0, 0.1026], [9565.5, 5.5332], [9565.0, 27.5243], [9563.5, 2.6], [9562.0, 0.0175], [9561.0, 2.0085], [9552.0, 1.6], [9550.5, 27.3399], [9550.0, 0.1046], [9548.0, 0.0175], [9544.0, 4.8197], [9542.5, 26.5754], [9542.0, 0.003], [9541.0, 0.0549], [9540.0, 0.1984], [9537.5, 0.0008], [9535.5, 0.0105], [9535.0, 1.514], [9534.5, 36.5858], [9532.5, 4.7798], [9531.0, 40.6564], [9525.0, 0.001], [9523.5, 1.6], [9522.0, 0.0894], [9521.0, 0.315], [9520.5, 5.4525], [9520.0, 0.07], [9518.0, 0.034], [9517.5, 4.0], [9513.0, 0.0175], [9512.5, 15.6016], [9512.0, 32.7882], [9511.5, 0.0482], [9510.5, 0.0482], [9510.0, 0.2999], [9509.0, 2.0], [9508.5, 0.0482], [9506.0, 0.0416], [9505.5, 0.0492], [9505.0, 0.2], [9502.5, 0.01], [9502.0, 0.01], [9501.5, 0.0592], [9501.0, 0.001], [9500.0, 3.4913], [9499.5, 39.8683], [9498.0, 4.6108], [9497.0, 0.0481], [9492.0, 41.3559], [9490.0, 1.1104], [9488.0, 0.0105], [9486.0, 5.4443], [9485.5, 0.0482], [9484.0, 4.0], [9482.0, 0.25], [9481.5, 2.0], [9481.0, 8.1572]], "asks": [[9602.5, 3.0], [9603.0, 2.8979], [9603.5, 54.49], [9604.0, 5.9982], [9604.5, 3.028], [9605.0, 4.657], [9606.5, 5.2512], [9607.0, 4.003], [9607.5, 4.011], [9608.0, 13.7505], [9608.5, 3.994], [9609.0, 2.974], [9609.5, 3.002], [9612.0, 10.298], [9612.5, 13.455], [9613.5, 3.013], [9614.0, 2.02], [9614.5, 3.359], [9615.0, 21.2429], [9616.0, 0.5], [9616.5, 0.01], [9617.0, 2.182], [9617.5, 23.0223], [9618.0, 0.0623], [9618.5, 1.5795], [9619.0, 0.3065], [9620.0, 3.9], [9621.0, 1.5], [9622.0, 1.5], [9622.5, 1.216], [9625.0, 1.0], [9625.5, 0.9477], [9626.0, 0.05], [9628.5, 1.1588], [9629.0, 1.4], [9630.0, 4.2332], [9630.5, 1.228], [9631.0, 1.5], [9631.5, 0.0104], [9632.5, 26.7529], [9633.0, 0.25], [9638.0, 1.0], [9640.0, 0.2], [9641.0, 1.001], [9642.0, 0.0175], [9643.0, 0.25], [9643.5, 1.6], [9644.0, 31.4166], [9646.5, 41.6609], [9649.5, 0.2], [9653.5, 1.5], [9656.5, 1.6], [9657.0, 0.2], [9658.0, 1.5], [9659.5, 4.7804], [9660.5, 43.3405], [9665.5, 40.6564], [9670.0, 0.1034], [9671.5, 4.9098], [9674.0, 0.25], [9678.0, 15.6016], [9678.5, 1.5], [9681.0, 34.9683], [9683.0, 0.2], [9683.5, 5.3845], [9684.5, 5.087], [9685.0, 0.1032], [9686.5, 0.0075], [9689.0, 1.6], [9691.0, 34.7472], [9692.0, 0.001], [9694.0, 0.5], [9695.0, 0.0109], [9696.5, 4.825], [9700.0, 1.0595], [9701.5, 2.0], [9702.0, 0.011], [9702.5, 0.01], [9706.0, 1.2], [9708.0, 0.0175], [9710.0, 39.153], [9712.0, 48.6163], [9712.5, 1.5], [9713.0, 8.1572], [9715.5, 0.5021], [9716.5, 2.0], [9719.0, 0.0245], [9721.0, 0.5], [9724.0, 0.251], [9726.0, 0.12], [9727.5, 0.5075], [9730.0, 0.015], [9732.0, 58.5394], [9733.0, 0.001], [9734.0, 20.0], [9743.0, 0.06], [9750.0, 9.5], [9755.0, 52.4404], [9757.0, 48.6121], [9764.0, 0.015]], "action": "partial"}}`)
err := f.wsHandleData(data)
if err != nil {
t.Error(err)
}
data = []byte(`{"channel": "orderbook", "market": "BTC-PERP", "type": "update", "data": {"time": 1589855831.5128105, "checksum": 365946911, "bids": [[9596.0, 4.2656], [9512.0, 32.7912]], "asks": [[9613.5, 4.012], [9702.0, 0.021]], "action": "update"}}`)
err = f.wsHandleData(data)
if err != nil {
t.Error(err)
}
}
func TestGetOTCQuoteStatus(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {
@@ -1558,30 +1381,6 @@ func TestModifyTriggerOrder(t *testing.T) {
}
}
func TestParsingWSOBData2(t *testing.T) {
t.Parallel()
data := []byte(`{"channel": "orderbook", "market": "PRIVBEAR/USD", "type": "partial", "data": {"time": 1593498757.0915809, "checksum": 87356415, "bids": [[1389.5, 5.1019], [1384.5, 16.6318], [1371.5, 23.5531], [1365.5, 23.3001], [1354.0, 26.758], [1352.5, 24.6891], [1337.5, 30.3091], [1333.5, 24.9583], [1323.0, 30.9597], [1302.0, 40.9241], [1282.5, 38.0319], [1272.5, 39.1436], [1084.5, 1.8934], [1080.0, 2.0595], [1075.0, 2.0527], [1069.0, 1.8077], [1053.5, 1.855], [1.0, 2.0]], "asks": [[1403.5, 6.8077], [1407.5, 17.6482], [1417.0, 14.6401], [1418.5, 22.6664], [1426.0, 20.3936], [1430.5, 34.2797], [1435.0, 30.6073], [1443.0, 20.2036], [1471.5, 35.5789], [1494.5, 29.2815], [1505.0, 30.9842], [1511.5, 39.4325], [1799.5, 1.7529], [1810.5, 2.0379], [1813.5, 2.0423], [1817.5, 2.0393], [1821.0, 1.7148], [86347.5, 9e-05], [94982.5, 0.0001], [104480.0, 0.0001], [114930.0, 0.00011], [126420.0, 0.00011], [139065.0, 0.00011], [152970.0, 0.00012], [168267.5, 0.00012], [185092.5, 0.00012], [223962.5, 0.00013], [246360.0, 0.00014], [270995.0, 0.00017], [1203602.5, 0.00013]], "action": "partial"}}`)
err := f.wsHandleData(data)
if err != nil {
t.Fatal(err)
}
data = []byte(`{"channel": "orderbook", "market": "DOGE-PERP", "type": "partial", "data": {"time": 1593395710.072698, "checksum": 2591057682, "bids": [[0.0023085, 507742.0], [0.002308, 7000.0], [0.0023075, 100000.0], [0.0023065, 324770.0], [0.002305, 46000.0], [0.0023035, 879600.0], [0.002303, 49000.0], [0.0023025, 1076421.0], [0.002296, 30511800.0], [0.002293, 3006300.0], [0.0022925, 1256349.0], [0.0022895, 11855700.0], [0.0022855, 1008960.0], [0.0022775, 1047578.0], [0.0022745, 3070200.0], [0.00227, 2939100.0], [0.002269, 1599711.0], [0.00226, 1671504.0], [0.00225, 1957119.0], [0.00224, 5225404.0], [0.0022395, 250.0], [0.002233, 2994000.0], [0.002229, 2336857.0], [0.002218, 2144227.0], [0.002205, 2101662.0], [0.0021985, 7406099.0], [0.0021915, 2470187.0], [0.0021775, 2690545.0], [0.0021755, 250.0], [0.002162, 2997201.0], [0.00215, 11464856.0], [0.002148, 16178857.0], [0.0021255, 11063510.0], [0.002119, 164239.0], [0.0020435, 19124572.0], [0.0020395, 18376430.0], [0.0020125, 1250.0], [0.0019655, 50.0], [0.001958, 97012.0], [0.001942, 50000.0], [0.001899, 50000.0], [0.001895, 1250.0], [0.001712, 2500.0], [0.0012075, 70190.0], [0.00112, 22321.0], [1.65e-05, 31889.0]], "asks": [[0.0023145, 359557.0], [0.0023155, 222497.0], [0.0023175, 40000.0], [0.002319, 879600.0], [0.0023195, 50000.0], [0.0023205, 1067334.0], [0.0023215, 45000.0], [0.002326, 33518100.0], [0.0023265, 1113997.0], [0.0023285, 1170756.0], [0.002331, 11855700.0], [0.002336, 1105442.0], [0.002344, 1244804.0], [0.002348, 3070200.0], [0.0023525, 1546561.0], [0.0023555, 2939100.0], [0.0023575, 2928000.0], [0.002362, 1509707.0], [0.0023725, 1786697.0], [0.002374, 5710.0], [0.0023795, 151098.0], [0.0023835, 1747428.0], [0.002385, 2994000.0], [0.002395, 1721532.0], [0.0024015, 5710.0], [0.002408, 2552142.0], [0.002422, 2188855.0], [0.002429, 5710.0], [0.0024295, 8441953.0], [0.002437, 2196750.0], [0.002445, 122574.0], [0.002454, 1974273.0], [0.0024565, 5710.0], [0.0024715, 2864643.0], [0.00248, 15238408.0], [0.002484, 5710.0], [0.002497, 16343646.0], [0.0025025, 12177084.0], [0.0025115, 5710.0], [0.002539, 5710.0], [0.002566, 16643688.0], [0.0025665, 5710.0], [0.002594, 5710.0], [0.002617, 50.0], [0.002623, 10.0], [0.0027685, 20825893.0], [0.003178, 50000.0], [0.003811, 68952.0], [0.0074, 41460.0]], "action": "partial"}}`)
err = f.wsHandleData(data)
if err != nil {
t.Error(err)
}
data = []byte(`{"channel": "orderbook", "market": "BTC-PERP", "type": "partial", "data": {"time": 1589855831.4606245, "checksum": 225973019, "bids": [[9602.0, 3.2903], [9601.5, 3.11], [9601.0, 2.1356], [9600.5, 3.0991], [9600.0, 8.014], [9599.5, 4.1571], [9599.0, 79.1846], [9598.5, 3.099], [9598.0, 3.985], [9597.5, 3.999], [9597.0, 16.4335], [9596.5, 4.006], [9596.0, 3.2596], [9595.0, 6.334], [9594.0, 3.5685], [9593.0, 14.2717], [9592.5, 0.5], [9591.0, 2.181], [9590.5, 40.4246], [9590.0, 1.0], [9589.0, 1.357], [9588.5, 0.4738], [9587.5, 0.15], [9587.0, 16.811], [9586.5, 1.2], [9586.0, 0.2], [9585.5, 1.0], [9584.5, 0.002], [9584.0, 1.51], [9583.5, 0.01], [9583.0, 1.4], [9582.5, 0.1], [9582.0, 24.7921], [9581.0, 2.087], [9580.5, 2.0], [9580.0, 0.1], [9579.0, 1.1588], [9578.0, 0.9477], [9577.5, 22.216], [9576.0, 0.2], [9574.0, 22.0], [9573.5, 1.0], [9572.0, 0.203], [9570.0, 0.1026], [9565.5, 5.5332], [9565.0, 27.5243], [9563.5, 2.6], [9562.0, 0.0175], [9561.0, 2.0085], [9552.0, 1.6], [9550.5, 27.3399], [9550.0, 0.1046], [9548.0, 0.0175], [9544.0, 4.8197], [9542.5, 26.5754], [9542.0, 0.003], [9541.0, 0.0549], [9540.0, 0.1984], [9537.5, 0.0008], [9535.5, 0.0105], [9535.0, 1.514], [9534.5, 36.5858], [9532.5, 4.7798], [9531.0, 40.6564], [9525.0, 0.001], [9523.5, 1.6], [9522.0, 0.0894], [9521.0, 0.315], [9520.5, 5.4525], [9520.0, 0.07], [9518.0, 0.034], [9517.5, 4.0], [9513.0, 0.0175], [9512.5, 15.6016], [9512.0, 32.7882], [9511.5, 0.0482], [9510.5, 0.0482], [9510.0, 0.2999], [9509.0, 2.0], [9508.5, 0.0482], [9506.0, 0.0416], [9505.5, 0.0492], [9505.0, 0.2], [9502.5, 0.01], [9502.0, 0.01], [9501.5, 0.0592], [9501.0, 0.001], [9500.0, 3.4913], [9499.5, 39.8683], [9498.0, 4.6108], [9497.0, 0.0481], [9492.0, 41.3559], [9490.0, 1.1104], [9488.0, 0.0105], [9486.0, 5.4443], [9485.5, 0.0482], [9484.0, 4.0], [9482.0, 0.25], [9481.5, 2.0], [9481.0, 8.1572]], "asks": [[9602.5, 3.0], [9603.0, 2.8979], [9603.5, 54.49], [9604.0, 5.9982], [9604.5, 3.028], [9605.0, 4.657], [9606.5, 5.2512], [9607.0, 4.003], [9607.5, 4.011], [9608.0, 13.7505], [9608.5, 3.994], [9609.0, 2.974], [9609.5, 3.002], [9612.0, 10.298], [9612.5, 13.455], [9613.5, 3.013], [9614.0, 2.02], [9614.5, 3.359], [9615.0, 21.2429], [9616.0, 0.5], [9616.5, 0.01], [9617.0, 2.182], [9617.5, 23.0223], [9618.0, 0.0623], [9618.5, 1.5795], [9619.0, 0.3065], [9620.0, 3.9], [9621.0, 1.5], [9622.0, 1.5], [9622.5, 1.216], [9625.0, 1.0], [9625.5, 0.9477], [9626.0, 0.05], [9628.5, 1.1588], [9629.0, 1.4], [9630.0, 4.2332], [9630.5, 1.228], [9631.0, 1.5], [9631.5, 0.0104], [9632.5, 26.7529], [9633.0, 0.25], [9638.0, 1.0], [9640.0, 0.2], [9641.0, 1.001], [9642.0, 0.0175], [9643.0, 0.25], [9643.5, 1.6], [9644.0, 31.4166], [9646.5, 41.6609], [9649.5, 0.2], [9653.5, 1.5], [9656.5, 1.6], [9657.0, 0.2], [9658.0, 1.5], [9659.5, 4.7804], [9660.5, 43.3405], [9665.5, 40.6564], [9670.0, 0.1034], [9671.5, 4.9098], [9674.0, 0.25], [9678.0, 15.6016], [9678.5, 1.5], [9681.0, 34.9683], [9683.0, 0.2], [9683.5, 5.3845], [9684.5, 5.087], [9685.0, 0.1032], [9686.5, 0.0075], [9689.0, 1.6], [9691.0, 34.7472], [9692.0, 0.001], [9694.0, 0.5], [9695.0, 0.0109], [9696.5, 4.825], [9700.0, 1.0595], [9701.5, 2.0], [9702.0, 0.011], [9702.5, 0.01], [9706.0, 1.2], [9708.0, 0.0175], [9710.0, 39.153], [9712.0, 48.6163], [9712.5, 1.5], [9713.0, 8.1572], [9715.5, 0.5021], [9716.5, 2.0], [9719.0, 0.0245], [9721.0, 0.5], [9724.0, 0.251], [9726.0, 0.12], [9727.5, 0.5075], [9730.0, 0.015], [9732.0, 58.5394], [9733.0, 0.001], [9734.0, 20.0], [9743.0, 0.06], [9750.0, 9.5], [9755.0, 52.4404], [9757.0, 48.6121], [9764.0, 0.015]], "action": "partial"}}`)
err = f.wsHandleData(data)
if err != nil {
t.Error(err)
}
data = []byte(`{"channel": "orderbook", "market": "BTC-PERP", "type": "update", "data": {"time": 1589855831.5128105, "checksum": 365946911, "bids": [[9596.0, 4.2656], [9512.0, 32.7912]], "asks": [[9613.5, 4.012], [9702.0, 0.021]], "action": "update"}}`)
err = f.wsHandleData(data)
if err != nil {
t.Error(err)
}
}
func TestGetSubaccounts(t *testing.T) {
t.Parallel()
if !areTestAPIKeysSet() {

View File

@@ -603,37 +603,42 @@ type WsOrderbookData struct {
// WsOrders stores ws orders' data
type WsOrders struct {
ID int64 `json:"id"`
ClientID string `json:"clientId"`
Market string `json:"market"`
OrderType string `json:"type"`
Side string `json:"side"`
Size float64 `json:"size"`
Price float64 `json:"price"`
ReduceOnly bool `json:"reduceOnly"`
IOC bool `json:"ioc"`
PostOnly bool `json:"postOnly"`
Status string `json:"status"`
FilledSize float64 `json:"filedSize"`
RemainingSize float64 `json:"remainingSize"`
AvgFillPrice float64 `json:"avgFillPrice"`
ID int64 `json:"id"`
ClientID string `json:"clientId"`
Market string `json:"market"`
OrderType string `json:"type"`
Side string `json:"side"`
Price float64 `json:"price"`
Size float64 `json:"size"`
Status string `json:"status"`
FilledSize float64 `json:"filledSize"`
RemainingSize float64 `json:"remainingSize"`
ReduceOnly bool `json:"reduceOnly"`
Liquidation bool `json:"liquidation"`
AvgFillPrice float64 `json:"avgFillPrice"`
PostOnly bool `json:"postOnly"`
IOC bool `json:"ioc"`
CreatedAt time.Time `json:"createdAt"`
}
// WsFills stores websocket fills' data
type WsFills struct {
Fee float64 `json:"fee"`
FeeRate float64 `json:"feeRate"`
Future string `json:"future"`
ID int64 `json:"id"`
Liquidity string `json:"liquidity"`
Market string `json:"market"`
OrderID int64 `json:"orderId"`
TradeID int64 `json:"tradeId"`
Price float64 `json:"price"`
Side string `json:"side"`
Size float64 `json:"size"`
Time time.Time `json:"time"`
OrderType string `json:"orderType"`
ID int64 `json:"id"`
Market string `json:"market"`
Future string `json:"future"`
BaseCurrency string `json:"baseCurrency"`
QuoteCurrency string `json:"quoteCurrency"`
Type string `json:"type"`
Side string `json:"side"`
Price float64 `json:"price"`
Size float64 `json:"size"`
OrderID int64 `json:"orderId"`
Time time.Time `json:"time"`
TradeID int64 `json:"tradeId"`
FeeRate float64 `json:"feeRate"`
Fee float64 `json:"fee"`
FeeCurrency string `json:"feeCurrency"`
Liquidity string `json:"liquidity"`
}
// WsSub has the data used to subscribe to a channel
@@ -678,7 +683,7 @@ type WsOrderDataStore struct {
type WsFillsDataStore struct {
Channel string `json:"channel"`
MessageType string `json:"type"`
FillsData WsFills `json:"fills"`
FillsData WsFills `json:"data"`
}
// TimeInterval represents interval enum.

View File

@@ -335,24 +335,6 @@ func (f *FTX) wsHandleData(respRaw []byte) error {
if err != nil {
return err
}
var oSide order.Side
oSide, err = order.StringToOrderSide(resultData.OrderData.Side)
if err != nil {
f.Websocket.DataHandler <- order.ClassificationError{
Exchange: f.Name,
Err: err,
}
}
var resp order.Detail
resp.Side = oSide
resp.Amount = resultData.OrderData.Size
resp.AssetType = assetType
resp.ClientOrderID = resultData.OrderData.ClientID
resp.Exchange = f.Name
resp.ExecutedAmount = resultData.OrderData.FilledSize
resp.ID = strconv.FormatInt(resultData.OrderData.ID, 10)
resp.Pair = pair
resp.RemainingAmount = resultData.OrderData.Size - resultData.OrderData.FilledSize
var orderVars OrderVars
orderVars, err = f.compatibleOrderVars(
resultData.OrderData.Side,
@@ -364,10 +346,24 @@ func (f *FTX) wsHandleData(respRaw []byte) error {
if err != nil {
return err
}
resp.Status = orderVars.Status
resp.Side = orderVars.Side
var resp order.Detail
resp.PostOnly = resultData.OrderData.PostOnly
resp.Price = resultData.OrderData.Price
resp.Amount = resultData.OrderData.Size
resp.AverageExecutedPrice = resultData.OrderData.AvgFillPrice
resp.ExecutedAmount = resultData.OrderData.FilledSize
resp.RemainingAmount = resultData.OrderData.Size - resultData.OrderData.FilledSize
resp.Cost = resp.AverageExecutedPrice * resp.Amount
// Fee: orderVars.Fee is incorrect.
resp.Exchange = f.Name
resp.ID = strconv.FormatInt(resultData.OrderData.ID, 10)
resp.ClientOrderID = resultData.OrderData.ClientID
resp.Type = orderVars.OrderType
resp.Fee = orderVars.Fee
resp.Side = orderVars.Side
resp.Status = orderVars.Status
resp.AssetType = assetType
resp.Date = resultData.OrderData.CreatedAt
resp.Pair = pair
f.Websocket.DataHandler <- &resp
case wsFills:
var resultData WsFillsDataStore

View File

@@ -0,0 +1,369 @@
package ftx
import (
"testing"
"time"
"github.com/thrasher-corp/gocryptotrader/currency"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
"github.com/thrasher-corp/gocryptotrader/exchanges/stream"
)
func parseRaw(t *testing.T, input string) interface{} {
t.Helper()
pairs := currency.Pairs{
currency.Pair{
Base: currency.BTC,
Quote: currency.USDT,
},
}
x := FTX{
exchange.Base{
CurrencyPairs: currency.PairsManager{
Pairs: map[asset.Item]*currency.PairStore{
asset.Spot: {
Available: pairs,
Enabled: pairs,
ConfigFormat: &currency.PairFormat{
Delimiter: "^",
Uppercase: true,
},
},
},
},
Websocket: &stream.Websocket{
DataHandler: make(chan interface{}, 1),
},
},
}
if err := x.wsHandleData([]byte(input)); err != nil {
t.Fatal(err)
}
return <-x.Websocket.DataHandler
}
func TestFTX_wsHandleData_Details(t *testing.T) {
const inputPartiallyCancelled = `{
"channel": "orders",
"type": "update",
"data": {
"id": 69350095302,
"clientId": "192ab87ae99970b79f624ef8bd783351",
"market": "BTC/USDT",
"type": "limit",
"side": "sell",
"price": 65536,
"size": 12,
"status": "closed",
"filledSize": 4,
"remainingSize": 8,
"reduceOnly": false,
"liquidation": false,
"avgFillPrice": 32768,
"postOnly": true,
"ioc": true,
"createdAt": "2021-08-08T10:35:02.649437+00:00"
}
}`
p := parseRaw(t, inputPartiallyCancelled)
x, ok := p.(*order.Detail)
if !ok {
t.Fatalf("have %T, want order.Detail", p)
}
// "reduceOnly" and "liquidation" do not have corresponding fields in
// order.Detail.
if x.ID != "69350095302" ||
x.ClientOrderID != "192ab87ae99970b79f624ef8bd783351" ||
x.Pair.Base.Item.Symbol != "BTC" ||
x.Pair.Quote.Item.Symbol != "USDT" ||
x.Type != order.Limit ||
x.Side != order.Sell ||
x.Price != 65536 ||
x.Amount != 12 ||
x.Status != order.PartiallyCancelled ||
x.ExecutedAmount != 4 ||
x.RemainingAmount != 8 ||
x.AverageExecutedPrice != 32768 ||
!x.PostOnly ||
!x.Date.Equal(time.Unix(1628418902, 649437000).UTC()) {
t.Error("parsed values do not match")
}
const inputFilled = `{
"channel": "orders",
"type": "update",
"data": {
"id": 69350095302,
"clientId": "192ab87ae99970b79f624ef8bd783351",
"market": "BTC/USDT",
"type": "limit",
"side": "sell",
"price": 65536,
"size": 12,
"status": "closed",
"filledSize": 12,
"remainingSize": 0,
"reduceOnly": false,
"liquidation": false,
"avgFillPrice": 32768,
"postOnly": true,
"ioc": true,
"createdAt": "2021-08-08T10:35:02.649437+00:00"
}
}`
if status := parseRaw(t, inputFilled).(*order.Detail).Status; status != order.Filled {
t.Errorf("have %s, want %s", status, order.Filled)
}
const inputCancelled = `{
"channel": "orders",
"type": "update",
"data": {
"id": 69350095302,
"clientId": "192ab87ae99970b79f624ef8bd783351",
"market": "BTC/USDT",
"type": "limit",
"side": "sell",
"price": 65536,
"size": 12,
"status": "closed",
"filledSize": 0,
"remainingSize": 12,
"reduceOnly": false,
"liquidation": false,
"avgFillPrice": 32768,
"postOnly": true,
"ioc": true,
"createdAt": "2021-08-08T10:35:02.649437+00:00"
}
}`
if status := parseRaw(t, inputCancelled).(*order.Detail).Status; status != order.Cancelled {
t.Errorf("have %s, want %s", status, order.Cancelled)
}
}
func TestFTX_wsHandleData_wsFills(t *testing.T) {
const input = `{
"channel": "fills",
"type": "update",
"data": {
"id": 1234567890,
"market": "MARKET",
"future": "FUTURE",
"baseCurrency": "BTC",
"quoteCurrency": "USDT",
"type": "order",
"side": "sell",
"price": 32768,
"size": 2,
"orderId": 23456789012,
"time": "2021-08-07T14:32:42.373010+00:00",
"tradeId": 3456789012,
"feeRate": 8,
"fee": 16,
"feeCurrency": "FTT",
"liquidity": "maker"
}
}`
p := parseRaw(t, input)
x, ok := p.(WsFills)
if !ok {
t.Fatalf("have %T, want ftx.WsFills", p)
}
if x.ID != 1234567890 ||
x.Market != "MARKET" ||
x.Future != "FUTURE" ||
x.BaseCurrency != "BTC" ||
x.QuoteCurrency != "USDT" ||
x.Type != "order" ||
x.Side != "sell" ||
x.Price != 32768 ||
x.Size != 2 ||
x.OrderID != 23456789012 ||
!x.Time.Equal(time.Unix(1628346762, 373010000).UTC()) ||
x.TradeID != 3456789012 ||
x.FeeRate != 8 ||
x.Fee != 16 ||
x.FeeCurrency != "FTT" ||
x.Liquidity != "maker" {
t.Error("parsed values do not match")
}
}
func TestParsingOrders(t *testing.T) {
t.Parallel()
data := []byte(`{
"channel": "fills",
"data": {
"id": 24852229,
"clientId": null,
"market": "XRP-PERP",
"type": "limit",
"side": "buy",
"size": 42353.0,
"price": 0.2977,
"reduceOnly": false,
"ioc": false,
"postOnly": false,
"status": "closed",
"filledSize": 0.0,
"remainingSize": 0.0,
"avgFillPrice": 0.2978
},
"type": "update"
}`)
err := f.wsHandleData(data)
if err != nil {
t.Error(err)
}
}
func TestParsingWSTradesData(t *testing.T) {
t.Parallel()
data := []byte(`{
"channel": "trades",
"market": "BTC-PERP",
"type": "update",
"data": [
{
"id": 44200173,
"price": 9761.0,
"size": 0.0008,
"side": "buy",
"liquidation": false,
"time": "2020-05-15T01:10:04.369194+00:00"
}
]
}`)
err := f.wsHandleData(data)
if err != nil {
t.Error(err)
}
}
func TestParsingWSTickerData(t *testing.T) {
t.Parallel()
data := []byte(`{
"channel": "ticker",
"market": "BTC-PERP",
"type": "update",
"data": {
"bid": 9760.5,
"ask": 9761.0,
"bidSize": 3.36,
"askSize": 71.8484,
"last": 9761.0,
"time": 1589505004.4237103
}
}`)
err := f.wsHandleData(data)
if err != nil {
t.Error(err)
}
}
func TestParsingWSOrdersData(t *testing.T) {
t.Parallel()
data := []byte(`{
"channel": "orders",
"data": {
"id": 24852229,
"clientId": null,
"market": "BTC-PERP",
"type": "limit",
"side": "buy",
"size": 42353.0,
"price": 0.2977,
"reduceOnly": false,
"ioc": false,
"postOnly": false,
"status": "closed",
"filledSize": 0.0,
"remainingSize": 0.0,
"avgFillPrice": 0.2978
},
"type": "update"
}`)
err := f.wsHandleData(data)
if err != nil {
t.Error(err)
}
}
func TestParsingMarketsData(t *testing.T) {
t.Parallel()
data := []byte(`{"channel": "markets",
"type": "partial",
"data": {
"ADA-0626": {
"name": "ADA-0626",
"enabled": true,
"priceIncrement": 5e-06,
"sizeIncrement": 1.0,
"type": "future",
"baseCurrency": null,
"quoteCurrency": null,
"restricted": false,
"underlying": "ADA",
"future": {
"name": "ADA-0626",
"underlying": "ADA",
"description": "Cardano June 2020 Futures",
"type": "future", "expiry": "2020-06-26T003:00:00+00:00",
"perpetual": false,
"expired": false,
"enabled": true,
"postOnly": false,
"imfFactor": 4e-05,
"underlyingDescription": "Cardano",
"expiryDescription": "June 2020",
"moveStart": null, "positionLimitWeight": 10.0,
"group": "quarterly"}}},
"action": "partial"
}`)
err := f.wsHandleData(data)
if err != nil {
t.Error(err)
}
}
func TestParsingWSOBData(t *testing.T) {
data := []byte(`{"channel": "orderbook", "market": "BTC-PERP", "type": "partial", "data": {"time": 1589855831.4606245, "checksum": 225973019, "bids": [[9602.0, 3.2903], [9601.5, 3.11], [9601.0, 2.1356], [9600.5, 3.0991], [9600.0, 8.014], [9599.5, 4.1571], [9599.0, 79.1846], [9598.5, 3.099], [9598.0, 3.985], [9597.5, 3.999], [9597.0, 16.4335], [9596.5, 4.006], [9596.0, 3.2596], [9595.0, 6.334], [9594.0, 3.5685], [9593.0, 14.2717], [9592.5, 0.5], [9591.0, 2.181], [9590.5, 40.4246], [9590.0, 1.0], [9589.0, 1.357], [9588.5, 0.4738], [9587.5, 0.15], [9587.0, 16.811], [9586.5, 1.2], [9586.0, 0.2], [9585.5, 1.0], [9584.5, 0.002], [9584.0, 1.51], [9583.5, 0.01], [9583.0, 1.4], [9582.5, 0.1], [9582.0, 24.7921], [9581.0, 2.087], [9580.5, 2.0], [9580.0, 0.1], [9579.0, 1.1588], [9578.0, 0.9477], [9577.5, 22.216], [9576.0, 0.2], [9574.0, 22.0], [9573.5, 1.0], [9572.0, 0.203], [9570.0, 0.1026], [9565.5, 5.5332], [9565.0, 27.5243], [9563.5, 2.6], [9562.0, 0.0175], [9561.0, 2.0085], [9552.0, 1.6], [9550.5, 27.3399], [9550.0, 0.1046], [9548.0, 0.0175], [9544.0, 4.8197], [9542.5, 26.5754], [9542.0, 0.003], [9541.0, 0.0549], [9540.0, 0.1984], [9537.5, 0.0008], [9535.5, 0.0105], [9535.0, 1.514], [9534.5, 36.5858], [9532.5, 4.7798], [9531.0, 40.6564], [9525.0, 0.001], [9523.5, 1.6], [9522.0, 0.0894], [9521.0, 0.315], [9520.5, 5.4525], [9520.0, 0.07], [9518.0, 0.034], [9517.5, 4.0], [9513.0, 0.0175], [9512.5, 15.6016], [9512.0, 32.7882], [9511.5, 0.0482], [9510.5, 0.0482], [9510.0, 0.2999], [9509.0, 2.0], [9508.5, 0.0482], [9506.0, 0.0416], [9505.5, 0.0492], [9505.0, 0.2], [9502.5, 0.01], [9502.0, 0.01], [9501.5, 0.0592], [9501.0, 0.001], [9500.0, 3.4913], [9499.5, 39.8683], [9498.0, 4.6108], [9497.0, 0.0481], [9492.0, 41.3559], [9490.0, 1.1104], [9488.0, 0.0105], [9486.0, 5.4443], [9485.5, 0.0482], [9484.0, 4.0], [9482.0, 0.25], [9481.5, 2.0], [9481.0, 8.1572]], "asks": [[9602.5, 3.0], [9603.0, 2.8979], [9603.5, 54.49], [9604.0, 5.9982], [9604.5, 3.028], [9605.0, 4.657], [9606.5, 5.2512], [9607.0, 4.003], [9607.5, 4.011], [9608.0, 13.7505], [9608.5, 3.994], [9609.0, 2.974], [9609.5, 3.002], [9612.0, 10.298], [9612.5, 13.455], [9613.5, 3.013], [9614.0, 2.02], [9614.5, 3.359], [9615.0, 21.2429], [9616.0, 0.5], [9616.5, 0.01], [9617.0, 2.182], [9617.5, 23.0223], [9618.0, 0.0623], [9618.5, 1.5795], [9619.0, 0.3065], [9620.0, 3.9], [9621.0, 1.5], [9622.0, 1.5], [9622.5, 1.216], [9625.0, 1.0], [9625.5, 0.9477], [9626.0, 0.05], [9628.5, 1.1588], [9629.0, 1.4], [9630.0, 4.2332], [9630.5, 1.228], [9631.0, 1.5], [9631.5, 0.0104], [9632.5, 26.7529], [9633.0, 0.25], [9638.0, 1.0], [9640.0, 0.2], [9641.0, 1.001], [9642.0, 0.0175], [9643.0, 0.25], [9643.5, 1.6], [9644.0, 31.4166], [9646.5, 41.6609], [9649.5, 0.2], [9653.5, 1.5], [9656.5, 1.6], [9657.0, 0.2], [9658.0, 1.5], [9659.5, 4.7804], [9660.5, 43.3405], [9665.5, 40.6564], [9670.0, 0.1034], [9671.5, 4.9098], [9674.0, 0.25], [9678.0, 15.6016], [9678.5, 1.5], [9681.0, 34.9683], [9683.0, 0.2], [9683.5, 5.3845], [9684.5, 5.087], [9685.0, 0.1032], [9686.5, 0.0075], [9689.0, 1.6], [9691.0, 34.7472], [9692.0, 0.001], [9694.0, 0.5], [9695.0, 0.0109], [9696.5, 4.825], [9700.0, 1.0595], [9701.5, 2.0], [9702.0, 0.011], [9702.5, 0.01], [9706.0, 1.2], [9708.0, 0.0175], [9710.0, 39.153], [9712.0, 48.6163], [9712.5, 1.5], [9713.0, 8.1572], [9715.5, 0.5021], [9716.5, 2.0], [9719.0, 0.0245], [9721.0, 0.5], [9724.0, 0.251], [9726.0, 0.12], [9727.5, 0.5075], [9730.0, 0.015], [9732.0, 58.5394], [9733.0, 0.001], [9734.0, 20.0], [9743.0, 0.06], [9750.0, 9.5], [9755.0, 52.4404], [9757.0, 48.6121], [9764.0, 0.015]], "action": "partial"}}`)
err := f.wsHandleData(data)
if err != nil {
t.Error(err)
}
data = []byte(`{"channel": "orderbook", "market": "BTC-PERP", "type": "update", "data": {"time": 1589855831.5128105, "checksum": 365946911, "bids": [[9596.0, 4.2656], [9512.0, 32.7912]], "asks": [[9613.5, 4.012], [9702.0, 0.021]], "action": "update"}}`)
err = f.wsHandleData(data)
if err != nil {
t.Error(err)
}
}
func TestParsingWSOBData2(t *testing.T) {
t.Parallel()
data := []byte(`{"channel": "orderbook", "market": "PRIVBEAR/USD", "type": "partial", "data": {"time": 1593498757.0915809, "checksum": 87356415, "bids": [[1389.5, 5.1019], [1384.5, 16.6318], [1371.5, 23.5531], [1365.5, 23.3001], [1354.0, 26.758], [1352.5, 24.6891], [1337.5, 30.3091], [1333.5, 24.9583], [1323.0, 30.9597], [1302.0, 40.9241], [1282.5, 38.0319], [1272.5, 39.1436], [1084.5, 1.8934], [1080.0, 2.0595], [1075.0, 2.0527], [1069.0, 1.8077], [1053.5, 1.855], [1.0, 2.0]], "asks": [[1403.5, 6.8077], [1407.5, 17.6482], [1417.0, 14.6401], [1418.5, 22.6664], [1426.0, 20.3936], [1430.5, 34.2797], [1435.0, 30.6073], [1443.0, 20.2036], [1471.5, 35.5789], [1494.5, 29.2815], [1505.0, 30.9842], [1511.5, 39.4325], [1799.5, 1.7529], [1810.5, 2.0379], [1813.5, 2.0423], [1817.5, 2.0393], [1821.0, 1.7148], [86347.5, 9e-05], [94982.5, 0.0001], [104480.0, 0.0001], [114930.0, 0.00011], [126420.0, 0.00011], [139065.0, 0.00011], [152970.0, 0.00012], [168267.5, 0.00012], [185092.5, 0.00012], [223962.5, 0.00013], [246360.0, 0.00014], [270995.0, 0.00017], [1203602.5, 0.00013]], "action": "partial"}}`)
err := f.wsHandleData(data)
if err != nil {
t.Fatal(err)
}
data = []byte(`{"channel": "orderbook", "market": "DOGE-PERP", "type": "partial", "data": {"time": 1593395710.072698, "checksum": 2591057682, "bids": [[0.0023085, 507742.0], [0.002308, 7000.0], [0.0023075, 100000.0], [0.0023065, 324770.0], [0.002305, 46000.0], [0.0023035, 879600.0], [0.002303, 49000.0], [0.0023025, 1076421.0], [0.002296, 30511800.0], [0.002293, 3006300.0], [0.0022925, 1256349.0], [0.0022895, 11855700.0], [0.0022855, 1008960.0], [0.0022775, 1047578.0], [0.0022745, 3070200.0], [0.00227, 2939100.0], [0.002269, 1599711.0], [0.00226, 1671504.0], [0.00225, 1957119.0], [0.00224, 5225404.0], [0.0022395, 250.0], [0.002233, 2994000.0], [0.002229, 2336857.0], [0.002218, 2144227.0], [0.002205, 2101662.0], [0.0021985, 7406099.0], [0.0021915, 2470187.0], [0.0021775, 2690545.0], [0.0021755, 250.0], [0.002162, 2997201.0], [0.00215, 11464856.0], [0.002148, 16178857.0], [0.0021255, 11063510.0], [0.002119, 164239.0], [0.0020435, 19124572.0], [0.0020395, 18376430.0], [0.0020125, 1250.0], [0.0019655, 50.0], [0.001958, 97012.0], [0.001942, 50000.0], [0.001899, 50000.0], [0.001895, 1250.0], [0.001712, 2500.0], [0.0012075, 70190.0], [0.00112, 22321.0], [1.65e-05, 31889.0]], "asks": [[0.0023145, 359557.0], [0.0023155, 222497.0], [0.0023175, 40000.0], [0.002319, 879600.0], [0.0023195, 50000.0], [0.0023205, 1067334.0], [0.0023215, 45000.0], [0.002326, 33518100.0], [0.0023265, 1113997.0], [0.0023285, 1170756.0], [0.002331, 11855700.0], [0.002336, 1105442.0], [0.002344, 1244804.0], [0.002348, 3070200.0], [0.0023525, 1546561.0], [0.0023555, 2939100.0], [0.0023575, 2928000.0], [0.002362, 1509707.0], [0.0023725, 1786697.0], [0.002374, 5710.0], [0.0023795, 151098.0], [0.0023835, 1747428.0], [0.002385, 2994000.0], [0.002395, 1721532.0], [0.0024015, 5710.0], [0.002408, 2552142.0], [0.002422, 2188855.0], [0.002429, 5710.0], [0.0024295, 8441953.0], [0.002437, 2196750.0], [0.002445, 122574.0], [0.002454, 1974273.0], [0.0024565, 5710.0], [0.0024715, 2864643.0], [0.00248, 15238408.0], [0.002484, 5710.0], [0.002497, 16343646.0], [0.0025025, 12177084.0], [0.0025115, 5710.0], [0.002539, 5710.0], [0.002566, 16643688.0], [0.0025665, 5710.0], [0.002594, 5710.0], [0.002617, 50.0], [0.002623, 10.0], [0.0027685, 20825893.0], [0.003178, 50000.0], [0.003811, 68952.0], [0.0074, 41460.0]], "action": "partial"}}`)
err = f.wsHandleData(data)
if err != nil {
t.Error(err)
}
data = []byte(`{"channel": "orderbook", "market": "BTC-PERP", "type": "partial", "data": {"time": 1589855831.4606245, "checksum": 225973019, "bids": [[9602.0, 3.2903], [9601.5, 3.11], [9601.0, 2.1356], [9600.5, 3.0991], [9600.0, 8.014], [9599.5, 4.1571], [9599.0, 79.1846], [9598.5, 3.099], [9598.0, 3.985], [9597.5, 3.999], [9597.0, 16.4335], [9596.5, 4.006], [9596.0, 3.2596], [9595.0, 6.334], [9594.0, 3.5685], [9593.0, 14.2717], [9592.5, 0.5], [9591.0, 2.181], [9590.5, 40.4246], [9590.0, 1.0], [9589.0, 1.357], [9588.5, 0.4738], [9587.5, 0.15], [9587.0, 16.811], [9586.5, 1.2], [9586.0, 0.2], [9585.5, 1.0], [9584.5, 0.002], [9584.0, 1.51], [9583.5, 0.01], [9583.0, 1.4], [9582.5, 0.1], [9582.0, 24.7921], [9581.0, 2.087], [9580.5, 2.0], [9580.0, 0.1], [9579.0, 1.1588], [9578.0, 0.9477], [9577.5, 22.216], [9576.0, 0.2], [9574.0, 22.0], [9573.5, 1.0], [9572.0, 0.203], [9570.0, 0.1026], [9565.5, 5.5332], [9565.0, 27.5243], [9563.5, 2.6], [9562.0, 0.0175], [9561.0, 2.0085], [9552.0, 1.6], [9550.5, 27.3399], [9550.0, 0.1046], [9548.0, 0.0175], [9544.0, 4.8197], [9542.5, 26.5754], [9542.0, 0.003], [9541.0, 0.0549], [9540.0, 0.1984], [9537.5, 0.0008], [9535.5, 0.0105], [9535.0, 1.514], [9534.5, 36.5858], [9532.5, 4.7798], [9531.0, 40.6564], [9525.0, 0.001], [9523.5, 1.6], [9522.0, 0.0894], [9521.0, 0.315], [9520.5, 5.4525], [9520.0, 0.07], [9518.0, 0.034], [9517.5, 4.0], [9513.0, 0.0175], [9512.5, 15.6016], [9512.0, 32.7882], [9511.5, 0.0482], [9510.5, 0.0482], [9510.0, 0.2999], [9509.0, 2.0], [9508.5, 0.0482], [9506.0, 0.0416], [9505.5, 0.0492], [9505.0, 0.2], [9502.5, 0.01], [9502.0, 0.01], [9501.5, 0.0592], [9501.0, 0.001], [9500.0, 3.4913], [9499.5, 39.8683], [9498.0, 4.6108], [9497.0, 0.0481], [9492.0, 41.3559], [9490.0, 1.1104], [9488.0, 0.0105], [9486.0, 5.4443], [9485.5, 0.0482], [9484.0, 4.0], [9482.0, 0.25], [9481.5, 2.0], [9481.0, 8.1572]], "asks": [[9602.5, 3.0], [9603.0, 2.8979], [9603.5, 54.49], [9604.0, 5.9982], [9604.5, 3.028], [9605.0, 4.657], [9606.5, 5.2512], [9607.0, 4.003], [9607.5, 4.011], [9608.0, 13.7505], [9608.5, 3.994], [9609.0, 2.974], [9609.5, 3.002], [9612.0, 10.298], [9612.5, 13.455], [9613.5, 3.013], [9614.0, 2.02], [9614.5, 3.359], [9615.0, 21.2429], [9616.0, 0.5], [9616.5, 0.01], [9617.0, 2.182], [9617.5, 23.0223], [9618.0, 0.0623], [9618.5, 1.5795], [9619.0, 0.3065], [9620.0, 3.9], [9621.0, 1.5], [9622.0, 1.5], [9622.5, 1.216], [9625.0, 1.0], [9625.5, 0.9477], [9626.0, 0.05], [9628.5, 1.1588], [9629.0, 1.4], [9630.0, 4.2332], [9630.5, 1.228], [9631.0, 1.5], [9631.5, 0.0104], [9632.5, 26.7529], [9633.0, 0.25], [9638.0, 1.0], [9640.0, 0.2], [9641.0, 1.001], [9642.0, 0.0175], [9643.0, 0.25], [9643.5, 1.6], [9644.0, 31.4166], [9646.5, 41.6609], [9649.5, 0.2], [9653.5, 1.5], [9656.5, 1.6], [9657.0, 0.2], [9658.0, 1.5], [9659.5, 4.7804], [9660.5, 43.3405], [9665.5, 40.6564], [9670.0, 0.1034], [9671.5, 4.9098], [9674.0, 0.25], [9678.0, 15.6016], [9678.5, 1.5], [9681.0, 34.9683], [9683.0, 0.2], [9683.5, 5.3845], [9684.5, 5.087], [9685.0, 0.1032], [9686.5, 0.0075], [9689.0, 1.6], [9691.0, 34.7472], [9692.0, 0.001], [9694.0, 0.5], [9695.0, 0.0109], [9696.5, 4.825], [9700.0, 1.0595], [9701.5, 2.0], [9702.0, 0.011], [9702.5, 0.01], [9706.0, 1.2], [9708.0, 0.0175], [9710.0, 39.153], [9712.0, 48.6163], [9712.5, 1.5], [9713.0, 8.1572], [9715.5, 0.5021], [9716.5, 2.0], [9719.0, 0.0245], [9721.0, 0.5], [9724.0, 0.251], [9726.0, 0.12], [9727.5, 0.5075], [9730.0, 0.015], [9732.0, 58.5394], [9733.0, 0.001], [9734.0, 20.0], [9743.0, 0.06], [9750.0, 9.5], [9755.0, 52.4404], [9757.0, 48.6121], [9764.0, 0.015]], "action": "partial"}}`)
err = f.wsHandleData(data)
if err != nil {
t.Error(err)
}
data = []byte(`{"channel": "orderbook", "market": "BTC-PERP", "type": "update", "data": {"time": 1589855831.5128105, "checksum": 365946911, "bids": [[9596.0, 4.2656], [9512.0, 32.7912]], "asks": [[9613.5, 4.012], [9702.0, 0.021]], "action": "update"}}`)
err = f.wsHandleData(data)
if err != nil {
t.Error(err)
}
}

View File

@@ -578,9 +578,9 @@ func (f *FTX) SubmitOrder(s *order.Submit) (order.SubmitResponse, error) {
tempResp, err := f.Order(fPair.String(),
s.Side.Lower(),
s.Type.Lower(),
"",
"",
"",
s.ReduceOnly,
s.ImmediateOrCancel,
s.PostOnly,
s.ClientOrderID,
s.Price,
s.Amount)

View File

@@ -118,37 +118,38 @@ type ModifyResponse struct {
// Each exchange has their own requirements, so not all fields
// are required to be populated
type Detail struct {
ImmediateOrCancel bool
HiddenOrder bool
FillOrKill bool
PostOnly bool
Leverage float64
Price float64
Amount float64
LimitPriceUpper float64
LimitPriceLower float64
TriggerPrice float64
TargetAmount float64
ExecutedAmount float64
RemainingAmount float64
Cost float64
Fee float64
Exchange string
InternalOrderID string
ID string
ClientOrderID string
AccountID string
ClientID string
WalletAddress string
Type Type
Side Side
Status Status
AssetType asset.Item
Date time.Time
CloseTime time.Time
LastUpdated time.Time
Pair currency.Pair
Trades []TradeHistory
ImmediateOrCancel bool
HiddenOrder bool
FillOrKill bool
PostOnly bool
Leverage float64
Price float64
Amount float64
LimitPriceUpper float64
LimitPriceLower float64
TriggerPrice float64
AverageExecutedPrice float64
TargetAmount float64
ExecutedAmount float64
RemainingAmount float64
Cost float64
Fee float64
Exchange string
InternalOrderID string
ID string
ClientOrderID string
AccountID string
ClientID string
WalletAddress string
Type Type
Side Side
Status Status
AssetType asset.Item
Date time.Time
CloseTime time.Time
LastUpdated time.Time
Pair currency.Pair
Trades []TradeHistory
}
// Filter contains all properties an order can be filtered for