fix: persist sell prices to DB and add WF filter bootstrap
- price_db: add sell_prices table (ensure/upsert/load/delete) - trader: restore _last_sell_prices from DB on startup so re-entry block survives restarts; persist each sell price immediately - market: retry chunk requests up to 3 times with backoff on 429 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -196,6 +196,56 @@ def load_recent_wins(ticker: str, n: int = 5) -> list[bool]:
|
||||
return [bool(r[0]) for r in rows]
|
||||
|
||||
|
||||
# ── 직전 매도가 영구 저장 (재시작 후 재매수 차단 유지용) ──────────────────────
|
||||
|
||||
def ensure_sell_prices_table() -> None:
|
||||
"""sell_prices 테이블이 없으면 생성."""
|
||||
ddl = """
|
||||
CREATE TABLE sell_prices (
|
||||
ticker VARCHAR2(20) NOT NULL PRIMARY KEY,
|
||||
price NUMBER(20,8) NOT NULL,
|
||||
updated_at TIMESTAMP DEFAULT SYSTIMESTAMP NOT NULL
|
||||
)
|
||||
"""
|
||||
with _conn() as conn:
|
||||
try:
|
||||
conn.cursor().execute(ddl)
|
||||
except oracledb.DatabaseError as e:
|
||||
if e.args[0].code != 955: # ORA-00955: 이미 존재
|
||||
raise
|
||||
|
||||
|
||||
def upsert_sell_price(ticker: str, price: float) -> None:
|
||||
"""직전 매도가 저장 또는 갱신."""
|
||||
sql = """
|
||||
MERGE INTO sell_prices s
|
||||
USING (SELECT :ticker AS ticker FROM dual) d
|
||||
ON (s.ticker = d.ticker)
|
||||
WHEN MATCHED THEN
|
||||
UPDATE SET price = :price, updated_at = SYSTIMESTAMP
|
||||
WHEN NOT MATCHED THEN
|
||||
INSERT (ticker, price) VALUES (:ticker, :price)
|
||||
"""
|
||||
with _conn() as conn:
|
||||
conn.cursor().execute(sql, {"ticker": ticker, "price": price})
|
||||
|
||||
|
||||
def load_sell_prices() -> dict[str, float]:
|
||||
"""저장된 직전 매도가 전체 로드."""
|
||||
with _conn() as conn:
|
||||
cur = conn.cursor()
|
||||
cur.execute("SELECT ticker, price FROM sell_prices")
|
||||
return {r[0]: float(r[1]) for r in cur.fetchall()}
|
||||
|
||||
|
||||
def delete_sell_price(ticker: str) -> None:
|
||||
"""매도가 기록 삭제 (더 이상 필요 없을 때)."""
|
||||
with _conn() as conn:
|
||||
conn.cursor().execute(
|
||||
"DELETE FROM sell_prices WHERE ticker = :ticker", {"ticker": ticker}
|
||||
)
|
||||
|
||||
|
||||
def load_positions() -> list[dict]:
|
||||
"""저장된 전체 포지션 로드."""
|
||||
sql = """
|
||||
|
||||
Reference in New Issue
Block a user