Skip to content

Commit a23eaff

Browse files
author
Karl Ranna
authored
Follow-up fixes for Kraken support (#94)
* fix(kraken): add trading_agreement param to createOrder * fix(opendex): reduce order quantities by buffer amount * fix(cex): round order quantity to 4 decimals * feat: increase minimum CEX order limits
1 parent 1b207d6 commit a23eaff

File tree

5 files changed

+173
-30
lines changed

5 files changed

+173
-30
lines changed

src/centralized/ccxt/create-order.spec.ts

Lines changed: 140 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,175 @@
1-
import { createOrder$ } from './create-order';
1+
import BigNumber from 'bignumber.js';
22
import { Exchange } from 'ccxt';
3+
import { Config } from '../../config';
34
import { OrderSide } from '../../constants';
4-
import BigNumber from 'bignumber.js';
55
import { testConfig } from '../../test-utils';
6-
import { merge } from 'rxjs';
6+
import { createOrder$ } from './create-order';
77

88
describe('CCXT', () => {
9-
it('creates market orders', done => {
10-
expect.assertions(5);
9+
let orderQuantity: BigNumber;
10+
beforeEach(() => {
11+
orderQuantity = new BigNumber('0.01');
12+
});
13+
14+
it('Binance ETHBTC sell order', done => {
15+
expect.assertions(3);
16+
const orderResponse = 'orderResponse';
17+
const createMarketOrder = jest.fn(() => Promise.resolve(orderResponse));
18+
const exchange = ({
19+
createMarketOrder,
20+
} as unknown) as Exchange;
21+
const config: Config = {
22+
...testConfig(),
23+
...{
24+
BASEASSET: 'ETH',
25+
QUOTEASSET: 'BTC',
26+
CEX: 'Binance',
27+
},
28+
};
29+
const expectedSymbol = `${config.BASEASSET}/${config.QUOTEASSET}`;
30+
const sellOrder$ = createOrder$({
31+
config,
32+
exchange,
33+
side: OrderSide.SELL,
34+
quantity: orderQuantity,
35+
});
36+
sellOrder$.subscribe({
37+
next: actualOrderResponse => {
38+
expect(actualOrderResponse).toEqual(orderResponse);
39+
},
40+
complete: () => {
41+
expect(createMarketOrder).toHaveBeenCalledTimes(1);
42+
expect(createMarketOrder).toHaveBeenCalledWith(
43+
expectedSymbol,
44+
OrderSide.SELL,
45+
orderQuantity.toNumber(),
46+
undefined,
47+
undefined
48+
);
49+
done();
50+
},
51+
});
52+
});
53+
54+
it('Binance BTCUSDT buy order', done => {
55+
expect.assertions(3);
1156
const orderResponse = 'orderResponse';
1257
const createMarketOrder = jest.fn(() => Promise.resolve(orderResponse));
1358
const exchange = ({
1459
createMarketOrder,
1560
} as unknown) as Exchange;
16-
const config = testConfig();
17-
const orderQuantity = new BigNumber('0.01');
61+
const config: Config = {
62+
...testConfig(),
63+
...{
64+
BASEASSET: 'BTC',
65+
QUOTEASSET: 'USDT',
66+
CEX: 'Binance',
67+
},
68+
};
69+
orderQuantity = new BigNumber('0.12345678');
1870
const expectedSymbol = `${config.BASEASSET}/${config.QUOTEASSET}`;
1971
const buyOrder$ = createOrder$({
2072
config,
2173
exchange,
2274
side: OrderSide.BUY,
2375
quantity: orderQuantity,
2476
});
25-
const sellOrder$ = createOrder$({
77+
buyOrder$.subscribe({
78+
next: actualOrderResponse => {
79+
expect(actualOrderResponse).toEqual(orderResponse);
80+
},
81+
complete: () => {
82+
expect(createMarketOrder).toHaveBeenCalledTimes(1);
83+
expect(createMarketOrder).toHaveBeenCalledWith(
84+
expectedSymbol,
85+
OrderSide.BUY,
86+
0.1234,
87+
undefined,
88+
undefined
89+
);
90+
done();
91+
},
92+
});
93+
});
94+
95+
it('Kraken BTCUSDT buy order', done => {
96+
expect.assertions(3);
97+
const orderResponse = 'orderResponse';
98+
const createMarketOrder = jest.fn(() => Promise.resolve(orderResponse));
99+
const exchange = ({
100+
createMarketOrder,
101+
} as unknown) as Exchange;
102+
const config: Config = {
103+
...testConfig(),
104+
...{
105+
BASEASSET: 'BTC',
106+
QUOTEASSET: 'USDT',
107+
CEX: 'Kraken',
108+
},
109+
};
110+
const expectedSymbol = `${config.BASEASSET}/${config.QUOTEASSET}`;
111+
const buyOrder$ = createOrder$({
26112
config,
27113
exchange,
28-
side: OrderSide.SELL,
114+
side: OrderSide.BUY,
29115
quantity: orderQuantity,
30116
});
31-
merge(buyOrder$, sellOrder$).subscribe({
117+
buyOrder$.subscribe({
32118
next: actualOrderResponse => {
33119
expect(actualOrderResponse).toEqual(orderResponse);
34120
},
35121
complete: () => {
36-
expect(createMarketOrder).toHaveBeenCalledTimes(2);
122+
expect(createMarketOrder).toHaveBeenCalledTimes(1);
37123
expect(createMarketOrder).toHaveBeenCalledWith(
38124
expectedSymbol,
39125
OrderSide.BUY,
40-
orderQuantity.toNumber()
126+
orderQuantity.toNumber(),
127+
undefined,
128+
expect.objectContaining({
129+
trading_agreement: 'agree',
130+
})
41131
);
132+
done();
133+
},
134+
});
135+
});
136+
137+
it('Kraken ETHBTC sell order', done => {
138+
expect.assertions(3);
139+
const orderResponse = 'orderResponse';
140+
const createMarketOrder = jest.fn(() => Promise.resolve(orderResponse));
141+
const exchange = ({
142+
createMarketOrder,
143+
} as unknown) as Exchange;
144+
const config: Config = {
145+
...testConfig(),
146+
...{
147+
BASEASSET: 'ETH',
148+
QUOTEASSET: 'BTC',
149+
CEX: 'Kraken',
150+
},
151+
};
152+
const expectedSymbol = `${config.BASEASSET}/${config.QUOTEASSET}`;
153+
const sellOrder$ = createOrder$({
154+
config,
155+
exchange,
156+
side: OrderSide.SELL,
157+
quantity: orderQuantity,
158+
});
159+
sellOrder$.subscribe({
160+
next: actualOrderResponse => {
161+
expect(actualOrderResponse).toEqual(orderResponse);
162+
},
163+
complete: () => {
164+
expect(createMarketOrder).toHaveBeenCalledTimes(1);
42165
expect(createMarketOrder).toHaveBeenCalledWith(
43166
expectedSymbol,
44167
OrderSide.SELL,
45-
orderQuantity.toNumber()
168+
orderQuantity.toNumber(),
169+
undefined,
170+
expect.objectContaining({
171+
trading_agreement: 'agree',
172+
})
46173
);
47174
done();
48175
},

src/centralized/ccxt/create-order.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,20 @@ const createOrder$ = ({
1717
side,
1818
quantity,
1919
}: CreateOrderParams): Observable<Order> => {
20-
return defer(() =>
21-
from(
20+
return defer(() => {
21+
const price = undefined;
22+
const params =
23+
config.CEX === 'Kraken' ? { trading_agreement: 'agree' } : undefined;
24+
return from(
2225
exchange.createMarketOrder(
2326
`${config.BASEASSET}/${config.QUOTEASSET}`,
2427
side,
25-
quantity.toNumber()
28+
parseFloat(quantity.toFixed(4, BigNumber.ROUND_DOWN)),
29+
price,
30+
params
2631
)
27-
)
28-
);
32+
);
33+
});
2934
};
3035

3136
export { createOrder$, CreateOrderParams };

src/centralized/minimum-order-quantity-filter.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ type MinimumCEXquantities = {
99
};
1010

1111
const MINIMUM_ORDER_SIZE: MinimumCEXquantities = {
12-
BTC: new BigNumber('0.0001'),
13-
ETH: new BigNumber('0.005'),
14-
DAI: new BigNumber('10'),
15-
USDT: new BigNumber('10'),
12+
BTC: new BigNumber('0.001'),
13+
ETH: new BigNumber('0.05'),
14+
DAI: new BigNumber('15'),
15+
USDT: new BigNumber('15'),
1616
};
1717

1818
const quantityAboveMinimum = (asset: Asset) => {

src/opendex/orders.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ describe('tradeInfoToOpenDEXorders', () => {
7777
tradeInfo,
7878
expected: {
7979
buyPrice: new BigNumber('0.0188'),
80-
buyQuantity: new BigNumber('500'),
80+
buyQuantity: new BigNumber('495'),
8181
},
8282
});
8383
});
@@ -105,7 +105,7 @@ describe('tradeInfoToOpenDEXorders', () => {
105105
tradeInfo,
106106
expected: {
107107
buyPrice: new BigNumber('0.0188'),
108-
buyQuantity: new BigNumber('265.95744680'),
108+
buyQuantity: new BigNumber('263.29787234'),
109109
},
110110
});
111111
});
@@ -133,7 +133,7 @@ describe('tradeInfoToOpenDEXorders', () => {
133133
tradeInfo,
134134
expected: {
135135
buyPrice: new BigNumber('0.0188'),
136-
buyQuantity: new BigNumber('250'),
136+
buyQuantity: new BigNumber('247.5'),
137137
},
138138
});
139139
});
@@ -163,7 +163,7 @@ describe('tradeInfoToOpenDEXorders', () => {
163163
tradeInfo,
164164
expected: {
165165
sellPrice: new BigNumber('0.0212'),
166-
sellQuantity: new BigNumber('40'),
166+
sellQuantity: new BigNumber('39.6'),
167167
},
168168
});
169169
});
@@ -191,7 +191,7 @@ describe('tradeInfoToOpenDEXorders', () => {
191191
tradeInfo,
192192
expected: {
193193
sellPrice: new BigNumber('0.0212'),
194-
sellQuantity: new BigNumber('11.79245283'),
194+
sellQuantity: new BigNumber('11.67452830'),
195195
},
196196
});
197197
});
@@ -219,7 +219,7 @@ describe('tradeInfoToOpenDEXorders', () => {
219219
tradeInfo,
220220
expected: {
221221
sellPrice: new BigNumber('0.0212'),
222-
sellQuantity: new BigNumber('5'),
222+
sellQuantity: new BigNumber('4.95'),
223223
},
224224
});
225225
});

src/opendex/orders.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,20 +56,31 @@ const tradeInfoToOpenDEXorders = ({
5656
openDEXquoteAssetMaxOutbound.dividedBy(buyPrice),
5757
centralizedExchangeBaseAssetBalance
5858
);
59+
const BUFFER = new BigNumber('0.01');
60+
const buyQuantityWithBuffer = buyQuantity.minus(
61+
buyQuantity.multipliedBy(BUFFER)
62+
);
5963
const sellQuantity = BigNumber.minimum(
6064
openDEXbaseAssetMaxOutbound,
6165
openDEXquoteAssetMaxInbound.dividedBy(sellPrice),
6266
centralizedExchangeQuoteAssetBalance.dividedBy(price)
6367
);
68+
const sellQuantityWithBuffer = sellQuantity.minus(
69+
sellQuantity.multipliedBy(BUFFER)
70+
);
6471
const buyOrder = {
65-
quantity: coinsToSats(new BigNumber(buyQuantity.toFixed(8, 1)).toNumber()),
72+
quantity: coinsToSats(
73+
new BigNumber(buyQuantityWithBuffer.toFixed(8, 1)).toNumber()
74+
),
6675
orderSide: OrderSide.BUY,
6776
pairId,
6877
price: buyPrice.toNumber(),
6978
orderId: createOrderID(config, OrderSide.BUY),
7079
};
7180
const sellOrder = {
72-
quantity: coinsToSats(new BigNumber(sellQuantity.toFixed(8, 1)).toNumber()),
81+
quantity: coinsToSats(
82+
new BigNumber(sellQuantityWithBuffer.toFixed(8, 1)).toNumber()
83+
),
7384
orderSide: OrderSide.SELL,
7485
pairId,
7586
price: sellPrice.toNumber(),

0 commit comments

Comments
 (0)