Skip to content

Commit 31ca306

Browse files
committed
Allow LongBridge fractional sell orders
1 parent 96f88e3 commit 31ca306

2 files changed

Lines changed: 33 additions & 6 deletions

File tree

src/quant_platform_kit/longbridge/execution.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,29 @@ def submit_order(
4040
order_type = OrderType.LO if order_kind == "limit" else OrderType.MO
4141
order_side = OrderSide.Buy if side == "buy" else OrderSide.Sell
4242
submitted_quantity = Decimal(str(quantity))
43-
if submitted_quantity < Decimal("1") or submitted_quantity != submitted_quantity.to_integral_value():
43+
if submitted_quantity < Decimal("1"):
4444
return ExecutionReport(
4545
symbol=symbol.split(".")[0],
4646
side=side,
4747
quantity=float(quantity),
4848
status="rejected",
4949
raw_payload={
5050
"detail": (
51-
"LongBridge submitted_quantity must be a whole-share quantity "
52-
"of at least 1 share; "
51+
"LongBridge submitted_quantity must be at least 1 share; "
52+
f"got {submitted_quantity}."
53+
),
54+
"order_kind": order_kind,
55+
},
56+
)
57+
if side == "buy" and submitted_quantity != submitted_quantity.to_integral_value():
58+
return ExecutionReport(
59+
symbol=symbol.split(".")[0],
60+
side=side,
61+
quantity=float(quantity),
62+
status="rejected",
63+
raw_payload={
64+
"detail": (
65+
"LongBridge fractional buy orders are not supported by this adapter; "
5366
f"got {submitted_quantity}."
5467
),
5568
"order_kind": order_kind,

tests/test_longbridge_execution.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,10 @@ def test_submit_order_rejects_quantity_below_one_before_api_call(self) -> None:
102102
)
103103

104104
self.assertEqual(report.status, "rejected")
105-
self.assertIn("whole-share quantity of at least 1 share", report.raw_payload["detail"])
105+
self.assertIn("at least 1 share", report.raw_payload["detail"])
106106
self.assertFalse(hasattr(ctx, "submit_args"))
107107

108-
def test_submit_order_rejects_fractional_quantity_before_api_call(self) -> None:
108+
def test_submit_order_rejects_fractional_buy_before_api_call(self) -> None:
109109
longport_module = types.ModuleType("longport")
110110
openapi_module = types.ModuleType("longport.openapi")
111111
openapi_module.OrderSide = types.SimpleNamespace(Buy="Buy", Sell="Sell")
@@ -124,9 +124,23 @@ def test_submit_order_rejects_fractional_quantity_before_api_call(self) -> None:
124124
)
125125

126126
self.assertEqual(report.status, "rejected")
127-
self.assertIn("whole-share quantity of at least 1 share", report.raw_payload["detail"])
127+
self.assertIn("fractional buy orders are not supported", report.raw_payload["detail"])
128128
self.assertFalse(hasattr(ctx, "submit_args"))
129129

130+
def test_submit_order_allows_fractional_sell_at_or_above_one_share(self) -> None:
131+
longport_module = types.ModuleType("longport")
132+
openapi_module = types.ModuleType("longport.openapi")
133+
openapi_module.OrderSide = types.SimpleNamespace(Buy="Buy", Sell="Sell")
134+
openapi_module.OrderType = types.SimpleNamespace(LO="LO", MO="MO")
135+
openapi_module.TimeInForceType = types.SimpleNamespace(Day="Day")
136+
137+
ctx = FakeTradeContext()
138+
with patch.dict(sys.modules, {"longport": longport_module, "longport.openapi": openapi_module}):
139+
report = submit_order(ctx, "BOXX.US", order_kind="market", side="sell", quantity=4.6177)
140+
141+
self.assertEqual(report.status, "submitted")
142+
self.assertEqual(str(ctx.submit_args[3]), "4.6177")
143+
130144
def test_fetch_order_status(self) -> None:
131145
status = fetch_order_status(FakeTradeContext(), "OID-1")
132146

0 commit comments

Comments
 (0)