Skip to content

Commit 092f133

Browse files
committed
support global order quantity convert to okx contract size
1 parent 6d50e11 commit 092f133

File tree

4 files changed

+77
-1
lines changed

4 files changed

+77
-1
lines changed

pkg/exchange/okex/exchange.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@ func (e *Exchange) QueryMarkets(ctx context.Context) (types.MarketMap, error) {
170170
// OKEx does not offer minimal notional, use 1 USD here.
171171
MinNotional: fixedpoint.One,
172172
MinAmount: fixedpoint.One,
173+
174+
ContractValue: instrument.ContractValue,
173175
}
174176
markets[symbol] = market
175177
}
@@ -329,7 +331,10 @@ func (e *Exchange) SubmitOrder(ctx context.Context, order types.SubmitOrder) (*t
329331
orderReq.TradeMode(okexapi.TradeModeCross)
330332
}
331333
} else if e.IsFutures {
334+
quantity := order.Market.AdjustQuantityToContractSize(order.Quantity)
335+
orderReq.Size(order.Market.FormatQuantity(quantity))
332336
orderReq.InstrumentID(toLocalSymbol(order.Symbol, okexapi.InstrumentTypeSwap))
337+
333338
if e.FuturesSettings.IsIsolatedFutures {
334339
orderReq.TradeMode(okexapi.TradeModeIsolated)
335340
} else {

pkg/exchange/okex/okexapi/get_instruments_info_request.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ type InstrumentInfo struct {
1515
BaseCurrency string `json:"baseCcy"`
1616
QuoteCurrency string `json:"quoteCcy"`
1717
SettleCurrency string `json:"settleCcy"`
18-
ContractValue string `json:"ctVal"`
18+
ContractValue fixedpoint.Value `json:"ctVal"`
1919
ContractMultiplier string `json:"ctMult"`
2020
ContractValueCurrency string `json:"ctValCcy"`
2121
ListTime types.MillisecondTimestamp `json:"listTime"`

pkg/types/market.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ type Market struct {
5555

5656
MinPrice fixedpoint.Value `json:"minPrice,omitempty"`
5757
MaxPrice fixedpoint.Value `json:"maxPrice,omitempty"`
58+
59+
ContractValue fixedpoint.Value `json:"contractValue,omitempty"`
5860
}
5961

6062
func (m Market) IsDustQuantity(quantity, price fixedpoint.Value) bool {
@@ -265,6 +267,17 @@ func (m Market) AdjustQuantityByMaxAmount(quantity, currentPrice, maxAmount fixe
265267
return m.TruncateQuantity(quantity)
266268
}
267269

270+
// AdjustQuantityToContractSize adjusts the quantity to contract size
271+
func (m Market) AdjustQuantityToContractSize(quantity fixedpoint.Value) fixedpoint.Value {
272+
// Validate input parameters
273+
if quantity.Sign() <= 0 || m.ContractValue.Sign() <= 0 || m.StepSize.Sign() <= 0 {
274+
return fixedpoint.Zero
275+
}
276+
277+
contractQuantity := quantity.Div(m.ContractValue)
278+
return m.RoundUpByStepSize(contractQuantity)
279+
}
280+
268281
type MarketMap map[string]Market
269282

270283
func (m MarketMap) Add(market Market) {

pkg/types/market_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,3 +266,61 @@ func TestMarket_AdjustQuantityByMinNotional(t *testing.T) {
266266
assert.False(t, market.IsDustQuantity(q2, testCase.price))
267267
}
268268
}
269+
270+
func TestMarket_AdjustQuantityToContractSize(t *testing.T) {
271+
market := Market{
272+
Symbol: "BTCUSDT",
273+
StepSize: fixedpoint.NewFromFloat(0.01), // step size is 0.01 BTC
274+
ContractValue: fixedpoint.NewFromFloat(0.01), // 1 contract = 0.01 BTC
275+
VolumePrecision: 8,
276+
}
277+
278+
testCases := []struct {
279+
name string
280+
quantity fixedpoint.Value
281+
expect fixedpoint.Value
282+
}{
283+
{
284+
name: "exact contract size",
285+
quantity: fixedpoint.NewFromFloat(0.01), // 1 contract
286+
expect: fixedpoint.NewFromFloat(1.0),
287+
},
288+
{
289+
name: "multiple contracts",
290+
quantity: fixedpoint.NewFromFloat(0.05), // 5 contracts
291+
expect: fixedpoint.NewFromFloat(5.0),
292+
},
293+
{
294+
name: "round up to step size",
295+
quantity: fixedpoint.NewFromFloat(0.024), // 2.4 contracts
296+
expect: fixedpoint.NewFromFloat(2.4),
297+
},
298+
{
299+
name: "zero quantity",
300+
quantity: fixedpoint.Zero,
301+
expect: fixedpoint.Zero,
302+
},
303+
{
304+
name: "negative quantity",
305+
quantity: fixedpoint.NewFromFloat(-0.01),
306+
expect: fixedpoint.Zero,
307+
},
308+
{
309+
name: "small quantity",
310+
quantity: fixedpoint.NewFromFloat(0.005), // 0.5 contracts
311+
expect: fixedpoint.NewFromFloat(0.5),
312+
},
313+
{
314+
name: "large quantity",
315+
quantity: fixedpoint.NewFromFloat(1.0), // 100 contracts
316+
expect: fixedpoint.NewFromFloat(100.0),
317+
},
318+
}
319+
320+
for _, tc := range testCases {
321+
t.Run(tc.name, func(t *testing.T) {
322+
result := market.AdjustQuantityToContractSize(tc.quantity)
323+
assert.Equal(t, tc.expect, result, "quantity: %v", tc.quantity.Float64())
324+
})
325+
}
326+
}

0 commit comments

Comments
 (0)