signal_log: persist market snapshots
This commit is contained in:
+73
-7
@@ -7530,6 +7530,25 @@ def _make_log_report():
|
||||
reward_pips=8.8, pip_value=1.0, strategy="XAU_PB",
|
||||
trail_arm_r=0.70, trail_dist_r=0.85,
|
||||
)
|
||||
report.primary_analysis = TechnicalAnalysis(
|
||||
symbol="XAU/USD", timeframe=Timeframe.M5.value,
|
||||
timestamp=report.timestamp,
|
||||
indicators={
|
||||
"rsi": IndicatorSignal(
|
||||
"RSI", 62.5, SignalStrength.BUY, 70.0,
|
||||
"Momentum is bullish", 1.2),
|
||||
"atr": IndicatorSignal(
|
||||
"ATR", 5.25, SignalStrength.NEUTRAL, 0.0,
|
||||
"Volatility context", 0.0),
|
||||
},
|
||||
composite_signal=SignalStrength.BUY,
|
||||
composite_score=42.5,
|
||||
confidence=76.0,
|
||||
market_regime="trending_up",
|
||||
volatility_regime="normal",
|
||||
key_levels={"support": 2440.0, "atr": 5.25},
|
||||
pattern_signals=["bullish_engulfing"],
|
||||
)
|
||||
return report
|
||||
|
||||
|
||||
@@ -7547,7 +7566,10 @@ def _make_log_context():
|
||||
news_headlines=[NewsSentiment(
|
||||
headline="Fed signals rate hike", source="test",
|
||||
timestamp=now, currencies_mentioned=["USD", "XAU"],
|
||||
sentiment_score=1.0, keywords=["rate hike"])],
|
||||
sentiment_score=1.0, keywords=["rate hike"],
|
||||
sentiment_by_currency={"USD": 1.0, "XAU": -1.0},
|
||||
link="https://example.test/fed", description="Policy update",
|
||||
publisher="Example News")],
|
||||
calendar_available=True,
|
||||
llm_summary="Gold supported by soft dollar.",
|
||||
)
|
||||
@@ -7563,7 +7585,12 @@ def _():
|
||||
lg = slog.SignalLogger(path)
|
||||
report = _make_log_report()
|
||||
context = _make_log_context()
|
||||
lg.log(report, context=context, source="test", timeframe="M5")
|
||||
candles = {
|
||||
Timeframe.M5: make_ohlcv(20, seed=91),
|
||||
Timeframe.H1: make_ohlcv(10, seed=92),
|
||||
}
|
||||
lg.log(report, context=context, source="test", timeframe="M5",
|
||||
dataframes=candles)
|
||||
lg.close()
|
||||
conn = sqlite3.connect(path)
|
||||
rows = conn.execute("SELECT * FROM signals").fetchall()
|
||||
@@ -7600,7 +7627,21 @@ def _():
|
||||
headlines = json.loads(row["headlines_json"])
|
||||
assert headlines[0]["headline"] == "Fed signals rate hike"
|
||||
assert headlines[0]["score"] == 1.0
|
||||
assert headlines[0]["score_by_currency"]["XAU"] == -1.0
|
||||
assert headlines[0]["currencies"] == ["USD", "XAU"]
|
||||
assert headlines[0]["description"] == "Policy update"
|
||||
indicators = json.loads(row["indicators_json"])
|
||||
primary = indicators[Timeframe.M5.value]
|
||||
assert primary["composite_score"] == 42.5
|
||||
assert primary["indicators"]["rsi"]["signal"] == "BUY"
|
||||
assert primary["indicators"]["atr"]["value"] == 5.25
|
||||
candle_snapshot = json.loads(row["candles_json"])
|
||||
assert len(candle_snapshot[Timeframe.M5.value]) == 14
|
||||
assert len(candle_snapshot[Timeframe.H1.value]) == 10
|
||||
bar = candle_snapshot[Timeframe.M5.value][0]
|
||||
assert set(bar) == {"timestamp", "open", "high", "low", "close",
|
||||
"volume"}
|
||||
assert bar["timestamp"].endswith("+00:00")
|
||||
finally:
|
||||
slog.reset_loggers_for_tests()
|
||||
os.remove(path)
|
||||
@@ -7969,23 +8010,48 @@ def _():
|
||||
con.execute(
|
||||
"CREATE TABLE signals (id INTEGER PRIMARY KEY, logged_at TEXT,"
|
||||
" symbol TEXT, timeframe TEXT)")
|
||||
con.execute(
|
||||
"CREATE TABLE outlooks (id INTEGER PRIMARY KEY, logged_at TEXT,"
|
||||
" surface TEXT, bias TEXT, setup_forming TEXT, confidence REAL,"
|
||||
" watch TEXT, note TEXT)")
|
||||
con.commit()
|
||||
con.close()
|
||||
logger = slog.SignalLogger(path)
|
||||
columns = {
|
||||
row[1] for row in logger._conn.execute("PRAGMA table_info(signals)")
|
||||
}
|
||||
assert {"indicators_json", "candles_json"} <= columns
|
||||
outlook_columns = {
|
||||
row[1] for row in logger._conn.execute("PRAGMA table_info(outlooks)")
|
||||
}
|
||||
assert {"news_json", "indicators_json", "candles_json"} <= \
|
||||
outlook_columns
|
||||
result = mo.OutlookResult(
|
||||
bias="bearish", setup_forming="sell", confidence=71.5,
|
||||
watch="Wait for price to fail at resistance.",
|
||||
note="Momentum is fading after a sharp rise.", created_ts=time.time())
|
||||
rowid = logger.log_outlook(result, surface="test")
|
||||
payload = {
|
||||
"news": {"headlines": ["Gold firms"]},
|
||||
"indicators": {"1h": {"rsi": {"value": 55.0}}},
|
||||
"market_regime": {"1h": "trending_up"},
|
||||
"volatility_regime": {"1h": "normal"},
|
||||
"key_levels": {"1h": {"support": 4400.0}},
|
||||
"candles": {"1h": {"bars": [[-0.2, 0.1, -0.3, 0.0]]}},
|
||||
}
|
||||
rowid = logger.log_outlook(result, surface="test", payload=payload)
|
||||
logger.close()
|
||||
con = sqlite3.connect(path)
|
||||
row = con.execute(
|
||||
"SELECT surface, bias, setup_forming, confidence, watch, note "
|
||||
"SELECT surface, bias, setup_forming, confidence, watch, note, "
|
||||
"news_json, indicators_json, candles_json "
|
||||
"FROM outlooks WHERE id=?", (rowid,)).fetchone()
|
||||
con.close()
|
||||
assert row == ("test", "bearish", "sell", 71.5,
|
||||
"Wait for price to fail at resistance.",
|
||||
"Momentum is fading after a sharp rise.")
|
||||
assert row[:6] == ("test", "bearish", "sell", 71.5,
|
||||
"Wait for price to fail at resistance.",
|
||||
"Momentum is fading after a sharp rise.")
|
||||
assert json.loads(row[6])["headlines"] == ["Gold firms"]
|
||||
assert json.loads(row[7])["market_regime"]["1h"] == "trending_up"
|
||||
assert len(json.loads(row[8])["1h"]["bars"]) == 1
|
||||
finally:
|
||||
slog.reset_loggers_for_tests()
|
||||
os.remove(path)
|
||||
|
||||
Reference in New Issue
Block a user