Compare commits
5 Commits
feature/is
...
f58d42fdb0
| Author | SHA1 | Date | |
|---|---|---|---|
| f58d42fdb0 | |||
|
|
0b20251de0 | ||
| bffe6e9288 | |||
|
|
0146d1bf8a | ||
| 497564e75c |
@@ -346,8 +346,10 @@ class GeminiClient:
|
|||||||
# Validate required fields
|
# Validate required fields
|
||||||
if not all(k in data for k in ("action", "confidence", "rationale")):
|
if not all(k in data for k in ("action", "confidence", "rationale")):
|
||||||
logger.warning("Missing fields in Gemini response — defaulting to HOLD")
|
logger.warning("Missing fields in Gemini response — defaulting to HOLD")
|
||||||
|
# Preserve raw text in rationale so prompt_override callers (e.g. pre_market_planner)
|
||||||
|
# can extract their own JSON format from decision.rationale (#245)
|
||||||
return TradeDecision(
|
return TradeDecision(
|
||||||
action="HOLD", confidence=0, rationale="Missing required fields"
|
action="HOLD", confidence=0, rationale=raw
|
||||||
)
|
)
|
||||||
|
|
||||||
action = str(data["action"]).upper()
|
action = str(data["action"]).upper()
|
||||||
|
|||||||
@@ -179,8 +179,8 @@ class PromptOptimizer:
|
|||||||
# Minimal instructions
|
# Minimal instructions
|
||||||
prompt = (
|
prompt = (
|
||||||
f"{market_name} trader. Analyze:\n{data_str}\n\n"
|
f"{market_name} trader. Analyze:\n{data_str}\n\n"
|
||||||
'Return JSON: {"act":"BUY"|"SELL"|"HOLD","conf":<0-100>,"reason":"<text>"}\n'
|
'Return JSON: {"action":"BUY"|"SELL"|"HOLD","confidence":<0-100>,"rationale":"<text>"}\n'
|
||||||
"Rules: act=BUY/SELL/HOLD, conf=0-100, reason=concise. No markdown."
|
"Rules: action=BUY/SELL/HOLD, confidence=0-100, rationale=concise. No markdown."
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# Data only (for cached contexts where instructions are known)
|
# Data only (for cached contexts where instructions are known)
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ class OverseasBroker:
|
|||||||
"AUTH": "",
|
"AUTH": "",
|
||||||
"EXCD": ranking_excd,
|
"EXCD": ranking_excd,
|
||||||
"NDAY": "0",
|
"NDAY": "0",
|
||||||
"GUBN": "1",
|
"GUBN": "0", # 0=전체(상승+하락), 1=상승만 — 변동성 스캐너는 전체 필요
|
||||||
"VOL_RANG": "0",
|
"VOL_RANG": "0",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,9 +93,21 @@ class TestMalformedJsonHandling:
|
|||||||
|
|
||||||
def test_json_with_missing_fields_returns_hold(self, settings):
|
def test_json_with_missing_fields_returns_hold(self, settings):
|
||||||
client = GeminiClient(settings)
|
client = GeminiClient(settings)
|
||||||
decision = client.parse_response('{"action": "BUY"}')
|
raw = '{"action": "BUY"}'
|
||||||
|
decision = client.parse_response(raw)
|
||||||
assert decision.action == "HOLD"
|
assert decision.action == "HOLD"
|
||||||
assert decision.confidence == 0
|
assert decision.confidence == 0
|
||||||
|
# rationale preserves raw so prompt_override callers (e.g. pre_market_planner)
|
||||||
|
# can extract non-TradeDecision JSON from decision.rationale (#245)
|
||||||
|
assert decision.rationale == raw
|
||||||
|
|
||||||
|
def test_non_trade_decision_json_preserves_raw_in_rationale(self, settings):
|
||||||
|
"""Playbook JSON (no action/confidence/rationale) must be preserved for planner."""
|
||||||
|
client = GeminiClient(settings)
|
||||||
|
playbook_json = '{"market_outlook": "neutral", "stocks": []}'
|
||||||
|
decision = client.parse_response(playbook_json)
|
||||||
|
assert decision.action == "HOLD"
|
||||||
|
assert decision.rationale == playbook_json
|
||||||
|
|
||||||
def test_json_with_invalid_action_returns_hold(self, settings):
|
def test_json_with_invalid_action_returns_hold(self, settings):
|
||||||
client = GeminiClient(settings)
|
client = GeminiClient(settings)
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ class TestFetchOverseasRankings:
|
|||||||
assert "/uapi/overseas-stock/v1/ranking/updown-rate" in url
|
assert "/uapi/overseas-stock/v1/ranking/updown-rate" in url
|
||||||
assert params["EXCD"] == "NAS"
|
assert params["EXCD"] == "NAS"
|
||||||
assert params["NDAY"] == "0"
|
assert params["NDAY"] == "0"
|
||||||
assert params["GUBN"] == "1"
|
assert params["GUBN"] == "0" # 0=전체(상승+하락), 변동성 스캐너에 필요
|
||||||
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")
|
||||||
|
|||||||
@@ -124,6 +124,10 @@ class TestPromptOptimizer:
|
|||||||
assert len(prompt) < 300
|
assert len(prompt) < 300
|
||||||
assert "005930" in prompt
|
assert "005930" in prompt
|
||||||
assert "75000" in prompt
|
assert "75000" in prompt
|
||||||
|
# Keys must match parse_response expectations (#242)
|
||||||
|
assert '"action"' in prompt
|
||||||
|
assert '"confidence"' in prompt
|
||||||
|
assert '"rationale"' in prompt
|
||||||
|
|
||||||
def test_build_compressed_prompt_no_instructions(self):
|
def test_build_compressed_prompt_no_instructions(self):
|
||||||
"""Test compressed prompt without instructions."""
|
"""Test compressed prompt without instructions."""
|
||||||
|
|||||||
Reference in New Issue
Block a user