Paper trader: 00 per strategy, match live node 8-strategy set
- Capital: 00,000 -> 00 (8 x 00) - 12 old strategies -> 8 core strategies matching live node - Asset distribution: 4 BTC + 4 ETH - Removed Hawkes/DeepLOB/Cartea/Gueant/QueueImbalance imports - Added Kalman Pairs signal generation - All strategies share same signal logic as live node: BTC: OBI, Iceberg, Funding, A-S ETH: Pairs, Momentum, Mean Reversion, Kalman
This commit is contained in:
+50
-75
@@ -15,11 +15,6 @@ from collections import deque
|
|||||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from strategies.hawkes_ofi import HawkesOFI
|
|
||||||
from strategies.deep_lob import DeepLOB
|
|
||||||
from strategies.cartea_jaimungal import CarteaJaimungal
|
|
||||||
from strategies.queue_imbalance import QueueImbalance
|
|
||||||
from strategies.gueant import GueantMM
|
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s [paper] %(message)s", datefmt="%H:%M:%S")
|
logging.basicConfig(level=logging.INFO, format="%(asctime)s [paper] %(message)s", datefmt="%H:%M:%S")
|
||||||
log = logging.getLogger("ftdt-paper")
|
log = logging.getLogger("ftdt-paper")
|
||||||
@@ -28,7 +23,7 @@ log = logging.getLogger("ftdt-paper")
|
|||||||
|
|
||||||
MAINNET_API = "https://api.hyperliquid.xyz/info"
|
MAINNET_API = "https://api.hyperliquid.xyz/info"
|
||||||
METRICS_FILE = "/tmp/ftdt-paper-metrics.json"
|
METRICS_FILE = "/tmp/ftdt-paper-metrics.json"
|
||||||
STARTING_CAPITAL = 100000.0 # $100,000 paper trading capital
|
STARTING_CAPITAL = 800.0 # $800 total = 8 x $100 strategies
|
||||||
RESERVE = 30000.0
|
RESERVE = 30000.0
|
||||||
TAKER_FEE = 0.0005 # 5 bps taker
|
TAKER_FEE = 0.0005 # 5 bps taker
|
||||||
MAKER_FEE = 0.0002 # 2 bps maker
|
MAKER_FEE = 0.0002 # 2 bps maker
|
||||||
@@ -39,92 +34,63 @@ MIN_SIGNAL_STRENGTH = 0.25 # Minimum signal strength to overcome fees
|
|||||||
|
|
||||||
STRATEGIES = {
|
STRATEGIES = {
|
||||||
"Order Book Imbalance": {
|
"Order Book Imbalance": {
|
||||||
"allocation": 10000.0, "instrument": "BTC", "pnl": 0.0,
|
"allocation": 100.0, "instrument": "BTC", "pnl": 0.0,
|
||||||
"trades_today": 0, "wins": 0, "win_rate": 0.0, "status": "idle",
|
"trades_today": 0, "wins": 0, "win_rate": 0.0, "status": "idle",
|
||||||
"position": 0.0, "entry_price": 0.0, "fee_paid": 0.0,
|
"position": 0.0, "entry_price": 0.0, "fee_paid": 0.0,
|
||||||
"signals": [], "type": "reversal", "size": 0.002, "fee_model": "taker",
|
"signals": [], "type": "reversal", "size": 0.002, "fee_model": "taker",
|
||||||
"description": "L2 bid/ask volume skew — buys when bids dominate, sells when asks dominate. Mean-reverting at volume extremes.",
|
"description": "L2 bid/ask volume skew — buys when bids dominate, mean-reverting.",
|
||||||
},
|
},
|
||||||
"Iceberg Detection": {
|
"Iceberg Detection": {
|
||||||
"allocation": 10000.0, "instrument": "BTC", "pnl": 0.0,
|
"allocation": 100.0, "instrument": "BTC", "pnl": 0.0,
|
||||||
"trades_today": 0, "wins": 0, "win_rate": 0.0, "status": "idle",
|
|
||||||
"position": 0.0, "entry_price": 0.0, "fee_paid": 0.0,
|
|
||||||
"signals": [], "type": "momentum", "size": 0.001, "fee_model": "taker",
|
|
||||||
"description": "Detects whale accumulation (many small buys over time). Follows the smart money flow.",
|
|
||||||
},
|
|
||||||
"Funding Rate Arb": {
|
|
||||||
"allocation": 10000.0, "instrument": "BTC", "pnl": 0.0,
|
|
||||||
"trades_today": 0, "wins": 0, "win_rate": 0.0, "status": "idle",
|
|
||||||
"position": 0.0, "entry_price": 0.0, "fee_paid": 0.0,
|
|
||||||
"signals": [], "type": "carry", "size": 0.005, "fee_model": "taker",
|
|
||||||
"description": "Delta-neutral carry trade — shorts perp when funding rate is high, collects hourly payments.",
|
|
||||||
},
|
|
||||||
"Pairs Trading": {
|
|
||||||
"allocation": 10000.0, "instrument": "ETH", "pnl": 0.0,
|
|
||||||
"trades_today": 0, "wins": 0, "win_rate": 0.0, "status": "idle",
|
|
||||||
"position": 0.0, "entry_price": 0.0, "fee_paid": 0.0,
|
|
||||||
"signals": [], "type": "stat_arb", "size": 0.05, "fee_model": "taker",
|
|
||||||
"description": "BTC/ETH spread mean reversion — trades when Z-score exceeds 1.5 sigma. Pairs converge back to equilibrium.",
|
|
||||||
},
|
|
||||||
"Avellaneda-Stoikov": {
|
|
||||||
"allocation": 10000.0, "instrument": "BTC", "pnl": 0.0,
|
|
||||||
"trades_today": 0, "wins": 0, "win_rate": 0.0, "status": "idle",
|
|
||||||
"position": 0.0, "entry_price": 0.0, "fee_paid": 0.0,
|
|
||||||
"signals": [], "type": "market_making", "size": 0.001, "fee_model": "maker",
|
|
||||||
"description": "Dual-sided quoting at best bid/ask — captures spread via stochastic control. Simulated fill when spread is crossed.",
|
|
||||||
},
|
|
||||||
"Momentum Breakout": {
|
|
||||||
"allocation": 10000.0, "instrument": "BTC", "pnl": 0.0,
|
|
||||||
"trades_today": 0, "wins": 0, "win_rate": 0.0, "status": "idle",
|
"trades_today": 0, "wins": 0, "win_rate": 0.0, "status": "idle",
|
||||||
"position": 0.0, "entry_price": 0.0, "fee_paid": 0.0,
|
"position": 0.0, "entry_price": 0.0, "fee_paid": 0.0,
|
||||||
"signals": [], "type": "momentum", "size": 0.002, "fee_model": "taker",
|
"signals": [], "type": "momentum", "size": 0.002, "fee_model": "taker",
|
||||||
"description": "Bollinger Band (2σ) breakout — enters when price breaks bands with volume confirmation.",
|
"description": "Detects whale accumulation — follows smart money flow.",
|
||||||
|
},
|
||||||
|
"Funding Rate Arb": {
|
||||||
|
"allocation": 100.0, "instrument": "BTC", "pnl": 0.0,
|
||||||
|
"trades_today": 0, "wins": 0, "win_rate": 0.0, "status": "idle",
|
||||||
|
"position": 0.0, "entry_price": 0.0, "fee_paid": 0.0,
|
||||||
|
"signals": [], "type": "carry", "size": 0.002, "fee_model": "taker",
|
||||||
|
"description": "Delta-neutral carry — shorts perp when funding rate is high.",
|
||||||
|
},
|
||||||
|
"Pairs Trading": {
|
||||||
|
"allocation": 100.0, "instrument": "ETH", "pnl": 0.0,
|
||||||
|
"trades_today": 0, "wins": 0, "win_rate": 0.0, "status": "idle",
|
||||||
|
"position": 0.0, "entry_price": 0.0, "fee_paid": 0.0,
|
||||||
|
"signals": [], "type": "stat_arb", "size": 0.05, "fee_model": "taker",
|
||||||
|
"description": "BTC/ETH spread mean reversion — Z-score entry at 1.2σ.",
|
||||||
|
},
|
||||||
|
"Avellaneda-Stoikov": {
|
||||||
|
"allocation": 100.0, "instrument": "BTC", "pnl": 0.0,
|
||||||
|
"trades_today": 0, "wins": 0, "win_rate": 0.0, "status": "idle",
|
||||||
|
"position": 0.0, "entry_price": 0.0, "fee_paid": 0.0,
|
||||||
|
"signals": [], "type": "market_making", "size": 0.001, "fee_model": "maker",
|
||||||
|
"description": "Dual-sided quoting at best bid/ask — captures spread.",
|
||||||
|
},
|
||||||
|
"Momentum Breakout": {
|
||||||
|
"allocation": 100.0, "instrument": "ETH", "pnl": 0.0,
|
||||||
|
"trades_today": 0, "wins": 0, "win_rate": 0.0, "status": "idle",
|
||||||
|
"position": 0.0, "entry_price": 0.0, "fee_paid": 0.0,
|
||||||
|
"signals": [], "type": "momentum", "size": 0.01, "fee_model": "taker",
|
||||||
|
"description": "Bollinger Band 1.2σ breakout on ETH — higher vol momentum.",
|
||||||
},
|
},
|
||||||
"Mean Reversion": {
|
"Mean Reversion": {
|
||||||
"allocation": 10000.0, "instrument": "BTC", "pnl": 0.0,
|
"allocation": 100.0, "instrument": "ETH", "pnl": 0.0,
|
||||||
"trades_today": 0, "wins": 0, "win_rate": 0.0, "status": "idle",
|
"trades_today": 0, "wins": 0, "win_rate": 0.0, "status": "idle",
|
||||||
"position": 0.0, "entry_price": 0.0, "fee_paid": 0.0,
|
"position": 0.0, "entry_price": 0.0, "fee_paid": 0.0,
|
||||||
"signals": [], "type": "reversal", "size": 0.002, "fee_model": "taker",
|
"signals": [], "type": "reversal", "size": 0.01, "fee_model": "taker",
|
||||||
"description": "VWAP deviation — buys below VWAP, sells above. Oscillates around fair value.",
|
"description": "VWAP deviation 0.8σ on ETH — mean-reverts around fair value.",
|
||||||
},
|
},
|
||||||
"Hawkes OFI (new)": {
|
"Kalman Pairs": {
|
||||||
"allocation": 10000.0, "instrument": "BTC", "pnl": 0.0,
|
"allocation": 100.0, "instrument": "ETH", "pnl": 0.0,
|
||||||
"trades_today": 0, "wins": 0, "win_rate": 0.0, "status": "idle",
|
"trades_today": 0, "wins": 0, "win_rate": 0.0, "status": "idle",
|
||||||
"position": 0.0, "entry_price": 0.0, "fee_paid": 0.0,
|
"position": 0.0, "entry_price": 0.0, "fee_paid": 0.0,
|
||||||
"signals": [], "type": "hawkes", "size": 0.002, "fee_model": "taker",
|
"signals": [], "type": "stat_arb", "size": 0.04, "fee_model": "taker",
|
||||||
"description": "Hawkes process OFI — self-exciting point process model capturing clustered order flow. Predicts direction from buy/sell intensity imbalance. Academically rigorous stochastic process.",
|
"description": "Kalman-filter adaptive hedge ratio — tracks evolving BTC/ETH beta.",
|
||||||
},
|
|
||||||
"Deep LOB (new)": {
|
|
||||||
"allocation": 10000.0, "instrument": "BTC", "pnl": 0.0,
|
|
||||||
"trades_today": 0, "wins": 0, "win_rate": 0.0, "status": "idle",
|
|
||||||
"position": 0.0, "entry_price": 0.0, "fee_paid": 0.0,
|
|
||||||
"signals": [], "type": "deep_lob", "size": 0.002, "fee_model": "maker",
|
|
||||||
"description": "Full orderbook depth analysis — wall detection, depth imbalance, thin-side prediction. Uses 10 levels of LOB to find fair value and directional pressure.",
|
|
||||||
},
|
|
||||||
"Cartea-Jaimungal": {
|
|
||||||
"allocation": 10000.0, "instrument": "BTC", "pnl": 0.0,
|
|
||||||
"trades_today": 0, "wins": 0, "win_rate": 0.0, "status": "idle",
|
|
||||||
"position": 0.0, "entry_price": 0.0, "fee_paid": 0.0,
|
|
||||||
"signals": [], "type": "cartea", "size": 0.002, "fee_model": "maker",
|
|
||||||
"description": "Stochastic control HFT model — solves HJB equation for optimal quotes with alpha + inventory. Reservation price dynamically shifts to manage risk. (Cartea-Jaimungal 2015)",
|
|
||||||
},
|
|
||||||
"Queue Imbalance": {
|
|
||||||
"allocation": 10000.0, "instrument": "BTC", "pnl": 0.0,
|
|
||||||
"trades_today": 0, "wins": 0, "win_rate": 0.0, "status": "idle",
|
|
||||||
"position": 0.0, "entry_price": 0.0, "fee_paid": 0.0,
|
|
||||||
"signals": [], "type": "queue_imb", "size": 0.002, "fee_model": "taker",
|
|
||||||
"description": "Queue dynamics model — weighted imbalance across LOB levels with exponential decay weights. Detects adverse selection when price moves against queue dominance. (Stoikov-Sağlam framework)",
|
|
||||||
},
|
|
||||||
"Guéant Market Making": {
|
|
||||||
"allocation": 10000.0, "instrument": "BTC", "pnl": 0.0,
|
|
||||||
"trades_today": 0, "wins": 0, "win_rate": 0.0, "status": "idle",
|
|
||||||
"position": 0.0, "entry_price": 0.0, "fee_paid": 0.0,
|
|
||||||
"signals": [], "type": "gueant", "size": 0.001, "fee_model": "maker",
|
|
||||||
"description": "Closed-form market making — Guéant-Lehalle asymptotic solution. Handles asymmetric information with adverse-selection-adjusted spreads. Computationally efficient closed form.",
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
[dict] = []
|
||||||
trades_log: list[dict] = []
|
|
||||||
equity_history: list[dict] = []
|
equity_history: list[dict] = []
|
||||||
strategy_equity: dict = {name: deque(maxlen=300) for name in STRATEGIES}
|
strategy_equity: dict = {name: deque(maxlen=300) for name in STRATEGIES}
|
||||||
per_strategy_trades: dict = {name: deque(maxlen=200) for name in STRATEGIES}
|
per_strategy_trades: dict = {name: deque(maxlen=200) for name in STRATEGIES}
|
||||||
@@ -321,6 +287,15 @@ def compute_signals():
|
|||||||
STRATEGIES["Mean Reversion"]["signals"].append({"time":time.time(),"signal":"SELL","strength":dev})
|
STRATEGIES["Mean Reversion"]["signals"].append({"time":time.time(),"signal":"SELL","strength":dev})
|
||||||
elif dev < -1.5:
|
elif dev < -1.5:
|
||||||
STRATEGIES["Mean Reversion"]["signals"].append({"time":time.time(),"signal":"BUY","strength":abs(dev)})
|
STRATEGIES["Mean Reversion"]["signals"].append({"time":time.time(),"signal":"BUY","strength":abs(dev)})
|
||||||
|
# Kalman Pairs
|
||||||
|
from strategies.kalman_pairs import KalmanPairsTrader
|
||||||
|
try:
|
||||||
|
result = kalman_trader.step(eth, btc)
|
||||||
|
if result["signal"] != 0:
|
||||||
|
sig = "BUY_ETH" if result["signal"] > 0 else "SELL_ETH"
|
||||||
|
STRATEGIES["Kalman Pairs"]["signals"].append({"time":time.time(),"signal":sig,"strength":abs(result["z_score"])})
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
for s in STRATEGIES.values():
|
for s in STRATEGIES.values():
|
||||||
s["signals"] = s["signals"][-20:]
|
s["signals"] = s["signals"][-20:]
|
||||||
|
|||||||
Reference in New Issue
Block a user