fix: include exchange_code in latest BUY matching key (#323)
Some checks failed
Gitea CI / test (pull_request) Waiting to run
Gitea CI / test (push) Has been cancelled

This commit is contained in:
agentson
2026-02-28 14:38:53 +09:00
parent 13a6d6612a
commit 47aadcb4e7
3 changed files with 88 additions and 17 deletions

View File

@@ -290,22 +290,47 @@ def _resolve_session_id(*, market: str, session_id: str | None) -> str:
def get_latest_buy_trade(
conn: sqlite3.Connection, stock_code: str, market: str
conn: sqlite3.Connection,
stock_code: str,
market: str,
exchange_code: str | None = None,
) -> dict[str, Any] | None:
"""Fetch the most recent BUY trade for a stock and market."""
cursor = conn.execute(
"""
SELECT decision_id, price, quantity
FROM trades
WHERE stock_code = ?
AND market = ?
AND action = 'BUY'
AND decision_id IS NOT NULL
ORDER BY timestamp DESC
LIMIT 1
""",
(stock_code, market),
)
if exchange_code:
cursor = conn.execute(
"""
SELECT decision_id, price, quantity
FROM trades
WHERE stock_code = ?
AND market = ?
AND action = 'BUY'
AND decision_id IS NOT NULL
AND (
exchange_code = ?
OR exchange_code IS NULL
OR exchange_code = ''
)
ORDER BY
CASE WHEN exchange_code = ? THEN 0 ELSE 1 END,
timestamp DESC
LIMIT 1
""",
(stock_code, market, exchange_code, exchange_code),
)
else:
cursor = conn.execute(
"""
SELECT decision_id, price, quantity
FROM trades
WHERE stock_code = ?
AND market = ?
AND action = 'BUY'
AND decision_id IS NOT NULL
ORDER BY timestamp DESC
LIMIT 1
""",
(stock_code, market),
)
row = cursor.fetchone()
if not row:
return None

View File

@@ -1655,7 +1655,12 @@ async def trading_cycle(
logger.warning("Telegram notification failed: %s", exc)
if decision.action == "SELL" and order_succeeded:
buy_trade = get_latest_buy_trade(db_conn, stock_code, market.code)
buy_trade = get_latest_buy_trade(
db_conn,
stock_code,
market.code,
exchange_code=market.exchange_code,
)
if buy_trade and buy_trade.get("price") is not None:
buy_price = float(buy_trade["price"])
buy_qty = int(buy_trade.get("quantity") or 1)
@@ -2752,7 +2757,12 @@ async def run_daily_session(
continue
if decision.action == "SELL" and order_succeeded:
buy_trade = get_latest_buy_trade(db_conn, stock_code, market.code)
buy_trade = get_latest_buy_trade(
db_conn,
stock_code,
market.code,
exchange_code=market.exchange_code,
)
if buy_trade and buy_trade.get("price") is not None:
buy_price = float(buy_trade["price"])
buy_qty = int(buy_trade.get("quantity") or 1)

View File

@@ -3,7 +3,7 @@
import tempfile
import os
from src.db import get_open_position, init_db, log_trade
from src.db import get_latest_buy_trade, get_open_position, init_db, log_trade
def test_get_open_position_returns_latest_buy() -> None:
@@ -329,3 +329,39 @@ def test_log_trade_unknown_market_falls_back_to_unknown_session() -> None:
row = conn.execute("SELECT session_id FROM trades ORDER BY id DESC LIMIT 1").fetchone()
assert row is not None
assert row[0] == "UNKNOWN"
def test_get_latest_buy_trade_prefers_exchange_code_match() -> None:
conn = init_db(":memory:")
log_trade(
conn=conn,
stock_code="AAPL",
action="BUY",
confidence=80,
rationale="legacy",
quantity=10,
price=120.0,
market="US_NASDAQ",
exchange_code="",
decision_id="legacy-buy",
)
log_trade(
conn=conn,
stock_code="AAPL",
action="BUY",
confidence=85,
rationale="matched",
quantity=5,
price=125.0,
market="US_NASDAQ",
exchange_code="NASD",
decision_id="matched-buy",
)
matched = get_latest_buy_trade(
conn,
stock_code="AAPL",
market="US_NASDAQ",
exchange_code="NASD",
)
assert matched is not None
assert matched["decision_id"] == "matched-buy"