- Sidebar: 信号/模拟盘 section headers - Three paper trade entries: 全部持仓, V5.1模拟盘, V5.2模拟盘 (NEW badge) - Paper page reads strategy from URL query params - Suspense boundary for useSearchParams
7.4 KiB
V5.2 Development Task
Context
You are working on the dev branch of the ArbitrageEngine project.
This is a quantitative trading signal system with:
- Backend: Python (FastAPI + PostgreSQL)
- Frontend: Next.js + shadcn/ui + Tailwind
Database Connection
- Host: 34.85.117.248 (Cloud SQL)
- Port: 5432, DB: arb_engine, User: arb, Password: arb_engine_2026
What to Build (V5.2)
1. Strategy Configuration Framework
Create backend/strategies/ directory with JSON configs:
backend/strategies/v51_baseline.json:
{
"name": "v51_baseline",
"version": "5.1",
"threshold": 75,
"weights": {
"direction": 45,
"crowding": 20,
"environment": 15,
"confirmation": 15,
"auxiliary": 5
},
"accel_bonus": 5,
"tp_sl": {
"sl_multiplier": 2.0,
"tp1_multiplier": 1.5,
"tp2_multiplier": 3.0
},
"signals": ["cvd", "p99", "accel", "ls_ratio", "oi", "coinbase_premium"]
}
backend/strategies/v52_8signals.json:
{
"name": "v52_8signals",
"version": "5.2",
"threshold": 75,
"weights": {
"direction": 40,
"crowding": 25,
"environment": 15,
"confirmation": 20,
"auxiliary": 5
},
"accel_bonus": 5,
"tp_sl": {
"sl_multiplier": 2.0,
"tp1_multiplier": 1.5,
"tp2_multiplier": 3.0
},
"signals": ["cvd", "p99", "accel", "ls_ratio", "oi", "coinbase_premium", "funding_rate", "liquidation"]
}
2. Signal Engine Changes (signal_engine.py)
2a. Add FR scoring to evaluate_signal()
After the crowding section, add funding_rate scoring:
# Funding Rate scoring (拥挤层加分)
# Read from market_indicators table
funding_rate = to_float(self.market_indicators.get("funding_rate"))
fr_score = 0
if funding_rate is not None:
fr_abs = abs(funding_rate)
if fr_abs >= 0.001: # extreme ±0.1%
# Extreme: penalize if going WITH the crowd
if (direction == "LONG" and funding_rate > 0.001) or \
(direction == "SHORT" and funding_rate < -0.001):
fr_score = -5
else:
fr_score = 5
elif fr_abs >= 0.0003: # moderate ±0.03%
# Moderate: reward going AGAINST the crowd
if (direction == "LONG" and funding_rate < -0.0003) or \
(direction == "SHORT" and funding_rate > 0.0003):
fr_score = 5
else:
fr_score = 0
2b. Add liquidation scoring
# Liquidation scoring (确认层加分)
liq_score = 0
liq_data = self.fetch_recent_liquidations() # new method
if liq_data:
liq_long_usd = liq_data.get("long_usd", 0)
liq_short_usd = liq_data.get("short_usd", 0)
# Thresholds by symbol
thresholds = {"BTCUSDT": 500000, "ETHUSDT": 200000, "XRPUSDT": 100000, "SOLUSDT": 100000}
threshold = thresholds.get(self.symbol, 100000)
total = liq_long_usd + liq_short_usd
if total >= threshold:
if liq_short_usd > 0 and liq_long_usd > 0:
ratio = liq_short_usd / liq_long_usd
elif liq_short_usd > 0:
ratio = float('inf')
else:
ratio = 0
if ratio >= 2.0 and direction == "LONG":
liq_score = 5 # shorts getting liquidated, price going up
elif ratio <= 0.5 and direction == "SHORT":
liq_score = 5 # longs getting liquidated, price going down
2c. Add fetch_recent_liquidations method to SymbolState
def fetch_recent_liquidations(self, window_ms=300000):
"""Fetch last 5min liquidation totals from liquidations table"""
now_ms = int(time.time() * 1000)
cutoff = now_ms - window_ms
with get_sync_conn() as conn:
with conn.cursor() as cur:
cur.execute("""
SELECT
COALESCE(SUM(CASE WHEN side='SELL' THEN usd_value ELSE 0 END), 0) as long_liq,
COALESCE(SUM(CASE WHEN side='BUY' THEN usd_value ELSE 0 END), 0) as short_liq
FROM liquidations
WHERE symbol=%s AND trade_time >= %s
""", (self.symbol, cutoff))
row = cur.fetchone()
if row:
return {"long_usd": row[0], "short_usd": row[1]}
return None
2d. Add funding_rate to fetch_market_indicators
Add "funding_rate" to the indicator types:
for ind_type in ["long_short_ratio", "top_trader_position", "open_interest_hist", "coinbase_premium", "funding_rate"]:
And the extraction:
elif ind_type == "funding_rate":
indicators[ind_type] = float(val.get("lastFundingRate", 0))
2e. Update total_score calculation
Currently:
total_score = direction_score + accel_bonus + crowding_score + environment_score + confirmation_score + aux_score
Change to:
total_score = direction_score + accel_bonus + crowding_score + fr_score + environment_score + confirmation_score + liq_score + aux_score
2f. Update factors dict
Add fr_score and liq_score to the factors:
result["factors"] = {
...existing factors...,
"funding_rate": {"score": fr_score, "value": funding_rate},
"liquidation": {"score": liq_score, "long_usd": liq_data.get("long_usd", 0) if liq_data else 0, "short_usd": liq_data.get("short_usd", 0) if liq_data else 0},
}
2g. Change threshold from 60 to 75
In evaluate_signal, change:
# OLD
elif total_score >= 60 and not no_direction and not in_cooldown:
result["signal"] = direction
result["tier"] = "light"
# NEW: remove the 60 tier entirely, minimum is 75
Also update reverse signal threshold from 60 to 75: In main() loop:
# OLD
if existing_dir and eval_dir and existing_dir != eval_dir and result["score"] >= 60:
# NEW
if existing_dir and eval_dir and existing_dir != eval_dir and result["score"] >= 75:
3. Strategy field in paper_trades
Add SQL migration at top of init_schema() or in a migration:
ALTER TABLE paper_trades ADD COLUMN IF NOT EXISTS strategy VARCHAR(32) DEFAULT 'v51_baseline';
4. AB Test: Both strategies evaluate each cycle
In the main loop, evaluate signal twice (once per strategy config) and potentially open trades for both. Each trade records which strategy triggered it.
5. Frontend: Update paper/page.tsx
- Show strategy column in trade history table
- Show FR and liquidation scores in signal details
- Add strategy filter/tab (v51 vs v52)
6. API: Add strategy stats endpoint
In main.py, add /api/paper/stats-by-strategy that groups stats by strategy field.
Important Notes
- Keep ALL existing functionality working
- Don't break the existing V5.1 scoring - it should still work as strategy "v51_baseline"
- The FR data is already in market_indicators table (collected every 5min)
- The liquidation data is already in liquidations table
- Test with:
cd frontend && npm run buildto verify no frontend errors - Test backend:
python3 -c "from signal_engine import *; print('OK')"to verify imports - Port for dev testing: API=8100, Frontend=3300
- Total score CAN exceed 100 (that's by design)
Files to modify:
backend/signal_engine.py- core scoring changesbackend/main.py- new API endpointsbackend/db.py- add strategy column migrationfrontend/app/paper/page.tsx- UI updates- NEW:
backend/strategies/v51_baseline.json - NEW:
backend/strategies/v52_8signals.json
When completely finished, run this command to notify me: openclaw system event --text "Done: V5.2 core implementation complete - FR+liquidation scoring, threshold 75, strategy configs, AB test framework" --mode now