mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-14 07:26:47 +00:00
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:
@@ -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:
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
369
exchanges/ftx/ftx_websocket_test.go
Normal file
369
exchanges/ftx/ftx_websocket_test.go
Normal 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: ¤cy.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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user