Compare commits
6 Commits
42db5b3cc1
...
feature/is
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7aa5fedc12 | ||
|
|
3e777a5ab8 | ||
| f87c4dc2f0 | |||
|
|
8af5f564c3 | ||
| 06e4fc5597 | |||
|
|
b697b6d515 |
@@ -23,7 +23,7 @@ if [ -z "${APP_CMD:-}" ]; then
|
|||||||
|
|
||||||
dashboard_port="${DASHBOARD_PORT:-8080}"
|
dashboard_port="${DASHBOARD_PORT:-8080}"
|
||||||
|
|
||||||
APP_CMD="DASHBOARD_PORT=$dashboard_port $PYTHON_BIN -m src.main --mode=paper --dashboard"
|
APP_CMD="DASHBOARD_PORT=$dashboard_port $PYTHON_BIN -m src.main --mode=live --dashboard"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p "$LOG_DIR"
|
mkdir -p "$LOG_DIR"
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ class OverseasBroker:
|
|||||||
tr_id = self._broker._settings.OVERSEAS_RANKING_VOLUME_TR_ID
|
tr_id = self._broker._settings.OVERSEAS_RANKING_VOLUME_TR_ID
|
||||||
path = self._broker._settings.OVERSEAS_RANKING_VOLUME_PATH
|
path = self._broker._settings.OVERSEAS_RANKING_VOLUME_PATH
|
||||||
params: dict[str, str] = {
|
params: dict[str, str] = {
|
||||||
|
"KEYB": "", # NEXT KEY BUFF — Required, 공백
|
||||||
"AUTH": "",
|
"AUTH": "",
|
||||||
"EXCD": ranking_excd,
|
"EXCD": ranking_excd,
|
||||||
"MIXN": "0",
|
"MIXN": "0",
|
||||||
@@ -130,10 +131,11 @@ class OverseasBroker:
|
|||||||
tr_id = self._broker._settings.OVERSEAS_RANKING_FLUCT_TR_ID
|
tr_id = self._broker._settings.OVERSEAS_RANKING_FLUCT_TR_ID
|
||||||
path = self._broker._settings.OVERSEAS_RANKING_FLUCT_PATH
|
path = self._broker._settings.OVERSEAS_RANKING_FLUCT_PATH
|
||||||
params = {
|
params = {
|
||||||
|
"KEYB": "", # NEXT KEY BUFF — Required, 공백
|
||||||
"AUTH": "",
|
"AUTH": "",
|
||||||
"EXCD": ranking_excd,
|
"EXCD": ranking_excd,
|
||||||
"NDAY": "0",
|
"NDAY": "0",
|
||||||
"GUBN": "0", # 0=전체(상승+하락), 1=상승만 — 변동성 스캐너는 전체 필요
|
"GUBN": "1", # 0=하락율, 1=상승율 — 변동성 스캐너는 급등 종목 우선
|
||||||
"VOL_RANG": "0",
|
"VOL_RANG": "0",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ def get_open_position(
|
|||||||
"""Return open position if latest trade is BUY, else None."""
|
"""Return open position if latest trade is BUY, else None."""
|
||||||
cursor = conn.execute(
|
cursor = conn.execute(
|
||||||
"""
|
"""
|
||||||
SELECT action, decision_id, price, quantity
|
SELECT action, decision_id, price, quantity, timestamp
|
||||||
FROM trades
|
FROM trades
|
||||||
WHERE stock_code = ?
|
WHERE stock_code = ?
|
||||||
AND market = ?
|
AND market = ?
|
||||||
@@ -266,7 +266,7 @@ def get_open_position(
|
|||||||
row = cursor.fetchone()
|
row = cursor.fetchone()
|
||||||
if not row or row[0] != "BUY":
|
if not row or row[0] != "BUY":
|
||||||
return None
|
return None
|
||||||
return {"decision_id": row[1], "price": row[2], "quantity": row[3]}
|
return {"decision_id": row[1], "price": row[2], "quantity": row[3], "timestamp": row[4]}
|
||||||
|
|
||||||
|
|
||||||
def get_recent_symbols(
|
def get_recent_symbols(
|
||||||
|
|||||||
16
src/main.py
16
src/main.py
@@ -576,6 +576,22 @@ async def trading_cycle(
|
|||||||
market_data["rsi"] = candidate.rsi
|
market_data["rsi"] = candidate.rsi
|
||||||
market_data["volume_ratio"] = candidate.volume_ratio
|
market_data["volume_ratio"] = candidate.volume_ratio
|
||||||
|
|
||||||
|
# Enrich market_data with holding info for SELL/HOLD scenario conditions
|
||||||
|
open_pos = get_open_position(db_conn, stock_code, market.code)
|
||||||
|
if open_pos and current_price > 0:
|
||||||
|
entry_price = safe_float(open_pos.get("price"), 0.0)
|
||||||
|
if entry_price > 0:
|
||||||
|
market_data["unrealized_pnl_pct"] = (
|
||||||
|
(current_price - entry_price) / entry_price * 100
|
||||||
|
)
|
||||||
|
entry_ts = open_pos.get("timestamp")
|
||||||
|
if entry_ts:
|
||||||
|
try:
|
||||||
|
entry_date = datetime.fromisoformat(entry_ts).date()
|
||||||
|
market_data["holding_days"] = (datetime.now(UTC).date() - entry_date).days
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
pass
|
||||||
|
|
||||||
# 1.3. Record L7 real-time context (market-scoped keys)
|
# 1.3. Record L7 real-time context (market-scoped keys)
|
||||||
timeframe = datetime.now(UTC).isoformat()
|
timeframe = datetime.now(UTC).isoformat()
|
||||||
context_store.set_context(
|
context_store.set_context(
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ def mock_settings() -> Settings:
|
|||||||
KIS_APP_SECRET="test_secret",
|
KIS_APP_SECRET="test_secret",
|
||||||
KIS_ACCOUNT_NO="12345678-01",
|
KIS_ACCOUNT_NO="12345678-01",
|
||||||
GEMINI_API_KEY="test_gemini_key",
|
GEMINI_API_KEY="test_gemini_key",
|
||||||
|
MODE="paper", # Explicitly set to avoid .env MODE=live override
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -122,9 +123,10 @@ class TestFetchOverseasRankings:
|
|||||||
params = call_args[1]["params"]
|
params = call_args[1]["params"]
|
||||||
|
|
||||||
assert "/uapi/overseas-stock/v1/ranking/updown-rate" in url
|
assert "/uapi/overseas-stock/v1/ranking/updown-rate" in url
|
||||||
|
assert params["KEYB"] == "" # Required by KIS API spec
|
||||||
assert params["EXCD"] == "NAS"
|
assert params["EXCD"] == "NAS"
|
||||||
assert params["NDAY"] == "0"
|
assert params["NDAY"] == "0"
|
||||||
assert params["GUBN"] == "0" # 0=전체(상승+하락), 변동성 스캐너에 필요
|
assert params["GUBN"] == "1" # 1=상승율 — 변동성 스캐너는 급등 종목 우선
|
||||||
assert params["VOL_RANG"] == "0"
|
assert params["VOL_RANG"] == "0"
|
||||||
|
|
||||||
overseas_broker._broker._auth_headers.assert_called_with("HHDFS76290000")
|
overseas_broker._broker._auth_headers.assert_called_with("HHDFS76290000")
|
||||||
@@ -157,6 +159,7 @@ class TestFetchOverseasRankings:
|
|||||||
params = call_args[1]["params"]
|
params = call_args[1]["params"]
|
||||||
|
|
||||||
assert "/uapi/overseas-stock/v1/ranking/volume-surge" in url
|
assert "/uapi/overseas-stock/v1/ranking/volume-surge" in url
|
||||||
|
assert params["KEYB"] == "" # Required by KIS API spec
|
||||||
assert params["EXCD"] == "NYS"
|
assert params["EXCD"] == "NYS"
|
||||||
assert params["MIXN"] == "0"
|
assert params["MIXN"] == "0"
|
||||||
assert params["VOL_RANG"] == "0"
|
assert params["VOL_RANG"] == "0"
|
||||||
|
|||||||
Reference in New Issue
Block a user