rl_btc_v4_iql / constants.py
fbzu's picture
Upload folder using huggingface_hub
22d888b verified
"""Constants for RL BTC v4."""
from __future__ import annotations
from dataclasses import dataclass
from pathlib import Path
import pandas as pd
REPO_ROOT = Path(__file__).resolve().parents[1]
DEFAULT_DATA_PATH = (
REPO_ROOT / "binance-experiment" / "research_datasets" / "btc_updown_5m_augmented_v1.parquet"
)
STARTING_CASH = 50.0
DRAWDOWN_LIMIT = 0.40
DEFAULT_HISTORY_LENGTH = 30 # number of past observations to include in state
DEFAULT_EPISODE_SPAN_DAYS = 30
DEFAULT_EPISODE_STRIDE_DAYS = 15 # overlapping episodes for more data
DEFAULT_REBALANCE_TOLERANCE = 0.05
# ── Fee schedule (Crypto / BTC prediction markets) ────────────────────────
# Taker fee in basis points (0.072 = 7.2 bps).
# Maker fee = 0 (not modelled β€” all orders assumed market/taker).
# Fee formula: fee_usdc = shares Γ— fee_rate Γ— price Γ— (1 - price)
# Quadratic in price β€” highest near 0.50 (max uncertainty), zero at 0/1.
# Maker rebate (20%) is not applied since we model taker orders.
TAKER_FEE_RATE = 0.072
# ── Action space ──────────────────────────────────────────────────────────────
@dataclass(frozen=True)
class ActionSpec:
id: int
name: str
kind: str # "hold" | "target" | "reduce"
target_side: str | None # "YES" | "NO" | None
target_fraction: float # target exposure as fraction of equity
ACTIONS: tuple[ActionSpec, ...] = (
ActionSpec(0, "HOLD", "hold", None, 0.00),
ActionSpec(1, "FLAT", "target", None, 0.00),
ActionSpec(2, "YES_10", "target", "YES", 0.10),
ActionSpec(3, "YES_25", "target", "YES", 0.25),
ActionSpec(4, "YES_50", "target", "YES", 0.50),
ActionSpec(5, "NO_10", "target", "NO", 0.10),
ActionSpec(6, "NO_25", "target", "NO", 0.25),
ActionSpec(7, "NO_50", "target", "NO", 0.50),
)
ACTION_INDEX_BY_NAME: dict[str, int] = {s.name: s.id for s in ACTIONS}
N_ACTIONS: int = len(ACTIONS)
# ── Feature columns ───────────────────────────────────────────────────────────
MARKET_FEATURE_COLUMNS: list[str] = [
"obs_pos",
"seconds_since_open",
"seconds_to_close",
"market_progress",
"yes_bid_validated",
"yes_ask_validated",
"yes_mid_validated",
"yes_spread_validated",
"no_bid_validated",
"no_ask_validated",
"no_mid_validated",
"no_spread_validated",
"microprice_bias",
"abs_yes_mid_distance_from_even",
"price_return_from_open",
"mark_return_from_open_filled",
"index_return_from_open_filled",
"abs_mark_return_from_open_filled",
"rolling_vol_15m",
"rolling_vol_60m",
"taker_buy_ratio",
"buy_sell_imbalance",
"rolling_volume_15m",
"rolling_num_trades_15m",
"volume",
"num_trades",
"return_over_vol_15m",
"return_over_vol_60m",
"signed_move_x_time_remaining",
"imbalance_x_vol",
"funding_rate",
"funding_rate_prev",
"oi_delta_5m",
"oi_delta_15m",
"oi_delta_60m",
"long_short_ratio",
"hour_sin",
"hour_cos",
]
PORTFOLIO_FEATURE_COLUMNS: list[str] = [
"cash_fraction",
"equity_fraction",
"drawdown_fraction",
"position_side",
"position_fraction",
"position_shares",
"avg_entry_price",
"unrealized_pnl_fraction",
"steps_held_fraction",
]
# Normalisation stats will be fitted on training data