fix: domestic current price fetching and KRX tick unit rounding (#157)
Some checks failed
CI / test (pull_request) Has been cancelled
Some checks failed
CI / test (pull_request) Has been cancelled
**Problem 1 — Current price always 0** get_orderbook() used inquire-asking-price-exp-ccn which has no stck_prpr in output1 (only askp/bidp data). This caused every domestic BUY to be skipped with "no affordable quantity (cash=..., price=0.00)". **Problem 2 — KRX tick unit error on limit orders** Limit order prices were passed unrounded, triggering 호가단위 오류 in VTS. Also ORD_DVSN was wrongly set to "01" (시장가) for limit orders. **Fix** - Add kr_tick_unit(price) and kr_round_down(price) module-level helpers implementing KRX 7-tier price tick rules (1/5/10/50/100/500/1000원). - Add get_current_price(stock_code) → (price, change_pct, foreigner_net) using FHKST01010100 / inquire-price API (works in VTS, returns correct stck_prpr, prdy_ctrt, frgn_ntby_qty). - Fix send_order() ORD_DVSN: "00"=지정가, "01"=시장가 (was "01"/"06"). - Apply kr_round_down() to limit order price inside send_order(). - Replace both get_orderbook() calls in main.py with get_current_price(). - Update all 4 test_main.py mock sites to use get_current_price AsyncMock. **Tests added** (25 new tests, all 646 pass) - TestKrTickUnit: 13 parametrized boundary cases + 7 round-down cases - TestGetCurrentPrice: correct fields, correct API path/TR_ID, HTTP error - TestSendOrderTickRounding: tick rounding, ORD_DVSN 00/01 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -111,15 +111,7 @@ class TestTradingCycleTelegramIntegration:
|
||||
def mock_broker(self) -> MagicMock:
|
||||
"""Create mock broker."""
|
||||
broker = MagicMock()
|
||||
broker.get_orderbook = AsyncMock(
|
||||
return_value={
|
||||
"output1": {
|
||||
"stck_prpr": "50000",
|
||||
"frgn_ntby_qty": "100",
|
||||
"prdy_ctrt": "1.23",
|
||||
}
|
||||
}
|
||||
)
|
||||
broker.get_current_price = AsyncMock(return_value=(50000.0, 1.23, 100.0))
|
||||
broker.get_balance = AsyncMock(
|
||||
return_value={
|
||||
"output2": [
|
||||
@@ -823,11 +815,7 @@ class TestScenarioEngineIntegration:
|
||||
def mock_broker(self) -> MagicMock:
|
||||
"""Create mock broker with standard domestic data."""
|
||||
broker = MagicMock()
|
||||
broker.get_orderbook = AsyncMock(
|
||||
return_value={
|
||||
"output1": {"stck_prpr": "50000", "frgn_ntby_qty": "100", "prdy_ctrt": "2.50"}
|
||||
}
|
||||
)
|
||||
broker.get_current_price = AsyncMock(return_value=(50000.0, 2.50, 100.0))
|
||||
broker.get_balance = AsyncMock(
|
||||
return_value={
|
||||
"output2": [
|
||||
@@ -1249,9 +1237,7 @@ async def test_sell_updates_original_buy_decision_outcome() -> None:
|
||||
)
|
||||
|
||||
broker = MagicMock()
|
||||
broker.get_orderbook = AsyncMock(
|
||||
return_value={"output1": {"stck_prpr": "120", "frgn_ntby_qty": "0"}}
|
||||
)
|
||||
broker.get_current_price = AsyncMock(return_value=(120.0, 0.0, 0.0))
|
||||
broker.get_balance = AsyncMock(
|
||||
return_value={
|
||||
"output2": [
|
||||
@@ -1341,9 +1327,7 @@ async def test_hold_overridden_to_sell_when_stop_loss_triggered() -> None:
|
||||
)
|
||||
|
||||
broker = MagicMock()
|
||||
broker.get_orderbook = AsyncMock(
|
||||
return_value={"output1": {"stck_prpr": "95", "frgn_ntby_qty": "0", "prdy_ctrt": "-5.0"}}
|
||||
)
|
||||
broker.get_current_price = AsyncMock(return_value=(95.0, -5.0, 0.0))
|
||||
broker.get_balance = AsyncMock(
|
||||
return_value={
|
||||
"output2": [
|
||||
|
||||
Reference in New Issue
Block a user