Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
102 commits
Select commit Hold shift + click to select a range
8d668f0
feat(quant): scale-free ML direction model v2 + honest OOS eval script
JoTalbot Aug 14, 2026
cd0ee30
docs(coordination): record paper entry unblock (ML model v2)
JoTalbot Aug 14, 2026
03ac5a3
docs(coordination): record paper entry unblock in context
JoTalbot Aug 14, 2026
aa8832f
docs(coordination): session paper-fix deployment verification
JoTalbot Aug 14, 2026
05bd3fd
fix(quant): RL bridge onehot/features/clamp + drop dead tickers
JoTalbot Aug 14, 2026
96d716d
docs(coordination): close RL bridge and dead ticker items
JoTalbot Aug 14, 2026
9501cf2
feat(quant): backfill history, retrain ML/PPO, fix signal source sele…
JoTalbot Aug 14, 2026
35fff86
docs(coordination): record backfill + ML/PPO retrain stage
JoTalbot Aug 14, 2026
bda4d3b
feat(quant): orderbook research expansion + docs sync
JoTalbot Aug 14, 2026
ed6689b
docs(coordination): record orderbook research expansion
JoTalbot Aug 14, 2026
0e303a9
chore(quant): mm-watcher auto-runs market-making sim at 1000 snapshot…
JoTalbot Aug 14, 2026
e622845
fix(quant): bitstamp has no SOL/USDT - per-exchange symbol filter; in…
JoTalbot Aug 14, 2026
ac8dbb2
docs(coordination): orderbook watcher record
JoTalbot Aug 14, 2026
a4b1c6f
feat(quant): inventory-aware MM simulator v2 + WATCH signals in morni…
JoTalbot Aug 14, 2026
d306aac
docs(coordination): MM v2 research + morning brief WATCH
JoTalbot Aug 14, 2026
3be4cd2
fix(ops): health check watches current models (ppo_v9, catboost v2)
JoTalbot Aug 14, 2026
3e857ff
docs(coordination): disk cleanup + health check model paths
JoTalbot Aug 14, 2026
dce3ca0
docs(coordination): final MM run on 14.5k snapshots - negative verdict
JoTalbot Aug 14, 2026
3171c6b
feat(quant): WATCH backtest, ML drift monitor, feature experiment, re…
JoTalbot Aug 14, 2026
839c66a
docs(coordination): record WATCH verification + ML automation stage
JoTalbot Aug 14, 2026
ee84cae
chore(ops): sync orderbook unit to deployed state (6 exchanges, 5s in…
JoTalbot Aug 14, 2026
174c395
fix(quant): honest PPO OOS validation - clamp like inference bridge
JoTalbot Aug 14, 2026
db27bdb
fix(quant): apply action clamp to legacy train script validation too
JoTalbot Aug 14, 2026
ef0ee81
docs(coordination): record honest PPO OOS finding + horizon experiment
JoTalbot Aug 14, 2026
4b0a1e6
docs(coordination): record 10k backfill + retrain no-improvement result
JoTalbot Aug 14, 2026
4f5f269
feat(quant): monthly backtest of deployed Directional v2 rules
JoTalbot Aug 14, 2026
d70286b
feat(quant): monthly backtest --months window parameter
JoTalbot Aug 14, 2026
7c88f3a
feat(quant): strategy research - found positive-OOS trend-following LS
JoTalbot Aug 14, 2026
11de569
docs(coordination): record profitable strategy research result
JoTalbot Aug 14, 2026
9f95fbb
feat(quant): corrected engine - compounding + next-bar timing; MA-LS …
JoTalbot Aug 14, 2026
ed052f3
docs(coordination): record earning algorithm MA-LS finding
JoTalbot Aug 14, 2026
fd38614
docs(coordination): read-only project analysis session 2026-08-15
Aug 15, 2026
907b094
fix(ops): stop aios-groq-key restart loop, disk cleanup, context sync
Aug 15, 2026
4bcee48
docs(coordination): disable aios-gitcoin-algora-solver per owner requ…
JoTalbot Aug 15, 2026
0c209fa
fix(tg_bot): delete temp audio after whisper transcription and TTS reply
JoTalbot Aug 15, 2026
e4dea74
docs(coordination): whisper temp-audio cleanup + disk audit session
JoTalbot Aug 15, 2026
926dbf5
docs(coordination): disk cleanup 81->46pct per owner decision (ollama…
JoTalbot Aug 15, 2026
8d15868
docs(quant): 6-month backtest of deployed Directional v2 rules (2026-…
JoTalbot Aug 15, 2026
070ff2f
docs(coordination): 6m quant backtest session results
JoTalbot Aug 15, 2026
f266143
docs(quant): 6-month backtest no-ml-gate control run
JoTalbot Aug 15, 2026
c7e4e77
docs(coordination): no-ml-gate control backtest finding
JoTalbot Aug 15, 2026
5e452d6
feat(quant): free-profile signals-quality mode for monthly backtest +…
JoTalbot Aug 15, 2026
fb6b3a6
docs(coordination): free-profile signals quality measurement results
JoTalbot Aug 15, 2026
e889bfc
docs(quant): 1-year backtest of Directional v2 (owner, free ML/no-ML …
JoTalbot Aug 15, 2026
4bfd861
docs(coordination): 1y backtest results - 6m edge did not hold
JoTalbot Aug 15, 2026
13450ae
feat(quant): per-exchange 12-month 1h history backfill tool + data es…
JoTalbot Aug 15, 2026
2269f12
feat(quant): price-source selector (real allowlist venues) + 1y backt…
JoTalbot Aug 15, 2026
72c2e9e
docs(coordination): 1y allowlist-venue backtest confirms conclusions
JoTalbot Aug 15, 2026
6a472cb
feat(quant): winrate experiment battery (trend/ML-threshold/exits/bla…
JoTalbot Aug 15, 2026
573eb4e
docs(coordination): winrate experiments results - expectancy stays ne…
JoTalbot Aug 15, 2026
631323b
feat(quant): OOS profit experiments - hard trailing (trail=1.0) posit…
JoTalbot Aug 15, 2026
a266b6c
feat(quant): configurable exit params (TP/SL/trail) + paper profile t…
JoTalbot Aug 15, 2026
745008b
feat(quant): N1 robustness checks - jackknife over symbols + binance …
JoTalbot Aug 15, 2026
96d21b3
feat(quant): partial take-profit research + binance allowlist + A/B c…
JoTalbot Aug 15, 2026
b879b0a
feat(quant): all-exchange allowlist + ML cross-sectional & SHORT expe…
JoTalbot Aug 15, 2026
d2085e2
Merge branch 'agent/20260815-quant-trail-config' into agent/20260815-…
JoTalbot Aug 15, 2026
20e400f
feat(quant): production-accurate 3-month backtest of the current live…
JoTalbot Aug 15, 2026
e5cf0f6
feat(quant): timeframe x universe experiment (4h/top-liquidity) - no …
JoTalbot Aug 15, 2026
775623b
feat(quant): ML hypothesis F stage 1 - multi-timeframe features (nega…
JoTalbot Aug 15, 2026
1d112f8
feat(quant): F-2 funding-rate experiment - no edge (7th negative result)
JoTalbot Aug 15, 2026
cee8c5e
feat(quant): F-4 multi-horizon target experiment - no edge (8th negat…
JoTalbot Aug 15, 2026
fd19714
docs(quant): summary of 8 edge experiments - no positive expectancy i…
JoTalbot Aug 15, 2026
91d7c54
feat(portfolio): long-term DCA portfolio plan + paper tracker (daily …
JoTalbot Aug 15, 2026
6e75eb6
feat(quant): MM pilot prototype on collected orderbook data (stage 1)
JoTalbot Aug 15, 2026
a18adef
feat(quant): MM stage 2 - microstructure direction signal neutralizes…
JoTalbot Aug 15, 2026
a329769
feat(quant): MM stage 3 - websocket orderbook depth collector (binanc…
JoTalbot Aug 15, 2026
94902aa
feat(quant): MM signal validated on 29h x 18 pairs + DCA report + con…
JoTalbot Aug 15, 2026
cbb2efb
feat(quant): MM calibration (no edge on REST data) + 7-pair ws collec…
JoTalbot Aug 15, 2026
18b9f9c
feat(quant): live MM monitor + horizon test + weekly digest + daily f…
JoTalbot Aug 15, 2026
e2f6b8f
feat(quant): V4 prototype - MM signal emitter (model->Telegram) + liv…
JoTalbot Aug 15, 2026
bebfff9
feat(quant): trade-flow collector + /quant TG command + VA backtest +…
JoTalbot Aug 15, 2026
bfbcb13
feat(quant): trade-flow (buy_frac) in signal model + VA mode in DCA t…
JoTalbot Aug 15, 2026
c2a47e2
feat(quant): Q4 queue fill model + Q5 signal subscription infrastructure
JoTalbot Aug 15, 2026
a98f43c
feat(quant): R1 signal economics - gross PnL≈0, fees dominate; emitte…
JoTalbot Aug 15, 2026
51e9668
feat(quant): W1 best-price MM + W4 maker-entry signal economics + W3 …
JoTalbot Aug 15, 2026
2409513
feat(dca): A/B VA vs plain DCA portfolios + TG value chart + increase…
JoTalbot Aug 15, 2026
bb7b1ed
feat(quant): N1 crypto news sentiment collector (Gemini) + hourly timer
JoTalbot Aug 15, 2026
81ff711
feat(quant): P1 Fear&Greed context + P2 sentiment-price test tool + P…
JoTalbot Aug 15, 2026
70b576c
feat(quant): historical news pipeline (Wayback RSS + Gemini sentiment…
JoTalbot Aug 15, 2026
120c13a
test(quant): force-add rss fixture (gitignored by *.xml rule)
JoTalbot Aug 15, 2026
c2f27ca
feat(quant): local lexicon sentiment scorer (no LLM quota) + historic…
JoTalbot Aug 15, 2026
855a09a
feat(quant): macro/on-chain/derivatives predictive test - 10th negati…
JoTalbot Aug 15, 2026
193e9a0
feat(quant): 2-year backtest - honest OOS negative, but beats buy&hol…
JoTalbot Aug 15, 2026
35644ba
feat(quant): factor strategies on daily data - T2 (TS-momentum BTC SM…
JoTalbot Aug 16, 2026
ecdf3dd
feat(quant): T2 momentum paper loop live (daily SMA50 signal + TG ale…
JoTalbot Aug 16, 2026
d34cbc7
feat(quant): T2 ETH paper loop + T2 in /quant & weekly digest
JoTalbot Aug 16, 2026
96f43c6
feat(quant): T2 validation (5y/rolling/calibration) + expansion (SOL,…
JoTalbot Aug 16, 2026
d687006
feat(quant): T2 W1 3-asset portfolio + W5 OOS calibration (SMA50 robu…
JoTalbot Aug 16, 2026
ccc6596
feat(quant): T2 U4 price-discrepancy check in prod + U1/U3 findings +…
JoTalbot Aug 16, 2026
420bdc3
feat(quant): T2 expanded to 5 symbols + hysteresis 50/40 for BTC/ETH/SOL
JoTalbot Aug 16, 2026
5eff470
feat(quant): T2 Y4 Binance-primary prices; Y1/Y2/combo rejected after…
JoTalbot Aug 16, 2026
f3620da
docs(quant): deep internet research on trading strategies + MM verdict
JoTalbot Aug 16, 2026
6f05964
docs(quant): all 5 researched strategies tested & rejected on full-cy…
JoTalbot Aug 16, 2026
3af1279
docs(quant): month-ago forward test of T2 (honest: parity in choppy m…
JoTalbot Aug 16, 2026
2ad53c2
docs(quant): exact economics of real-money T2 (median year +27.6%, 31…
JoTalbot Aug 16, 2026
1221acf
docs(quant): big-profit scenarios - concentration (SOL+BNB CAGR 164%)…
JoTalbot Aug 16, 2026
6bf7fac
docs(quant): research of trading theories/rumors + repos/products app…
JoTalbot Aug 16, 2026
ed9756f
feat(quant): meta-labeling filter + Riskfolio weights + Freqtrade T2 …
JoTalbot Aug 16, 2026
64c7621
feat(quant): freqtrade T2 port - level-based entry + custom_exit exit…
JoTalbot Aug 16, 2026
fa31c39
feat(quant): freqtrade validation suite (references, binance download…
JoTalbot Aug 16, 2026
67931a5
feat(quant): T2 real-money executor scaffold (dry by default, risk ca…
JoTalbot Aug 16, 2026
d90bfac
docs(quant): freqtrade validation report + session journal + advisory…
JoTalbot Aug 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 42 additions & 8 deletions aios_core/quant/ml_predictor.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,14 @@

LOG_TAG = "[QuantMLPredictor]"

DEFAULT_FEATURES = ["open", "high", "low", "close", "volume", "ret1", "ema12", "ema26", "rsi", "vol_ma"]
# Scale-free features (v2 model, trained by scripts/quant_ml_eval_train.py).
# Identical scale across assets (BTC vs PEPE), which the old raw-price feature
# set lacked; order must match the training script exactly.
DEFAULT_FEATURES = [
"ret1", "ret3", "ret6", "ret12", "ret24",
"rsi", "bb_pos", "macd_norm", "ema_gap",
"vol_ratio", "vol_z", "bar_range_pct", "hl_pos",
]


class QuantMLPredictor:
Expand All @@ -42,8 +49,9 @@ def __init__(self, models_dir: Optional[Path] = None):

# ------------------------------------------------------------ loading ----
def _load_model(self) -> None:
"""Загрузить CatBoost-модель если она есть."""
"""Загрузить CatBoost-модель; v2 (scale-free features) приоритетнее."""
candidates = [
self.models_dir / "catboost_price_dir_v2.cbm",
self.models_dir / "catboost_price_dir.cbm",
self.models_dir / "catboost_price_dir.pkl",
]
Expand All @@ -69,24 +77,44 @@ def available(self) -> bool:

# -------------------------------------------------------- prediction ----
def _features_from_csv(self, csv_path: Path) -> Optional[list]:
"""Построить вектор признаков из последних строк CSV."""
"""Построить вектор признаков из последних строк CSV.

Формулы должны совпадать 1:1 с scripts/quant_ml_eval_train.py
(_compute_features) — модель v2 обучена на этих же признаках.
"""
try:
df = pd.read_csv(csv_path)
except Exception as e:
print(f"{LOG_TAG} [WARN] CSV {csv_path}: {e}")
return None
if len(df) < 26:
if len(df) < 40:
return None
df = df.sort_values("timestamp_ms")
df["close"] = pd.to_numeric(df["close"], errors="coerce")
df["volume"] = pd.to_numeric(df["volume"], errors="coerce")
g = df[["open", "high", "low", "close", "volume"]].copy()
g["ret1"] = g["close"].pct_change()
g["ret3"] = g["close"].pct_change(3)
g["ret6"] = g["close"].pct_change(6)
g["ret12"] = g["close"].pct_change(12)
g["ret24"] = g["close"].pct_change(24)
chg = g["close"].pct_change()
up = chg.clip(lower=0).rolling(14).mean()
down = (-chg.clip(upper=0)).rolling(14).mean()
g["rsi"] = 100.0 - 100.0 / (1.0 + up / down.replace(0, 1e-9))
bb_mid = g["close"].rolling(20).mean()
bb_std = g["close"].rolling(20).std()
g["bb_pos"] = ((g["close"] - bb_mid + 2 * bb_std) / (4 * bb_std).replace(0, 1e-9)).clip(0, 1)
g["ema12"] = g["close"].ewm(span=12).mean()
g["ema26"] = g["close"].ewm(span=26).mean()
g["rsi"] = 100 - 100 / (1 + g["close"].pct_change().rolling(14).mean() /
g["close"].pct_change().rolling(14).std().replace(0, 1e-9))
g["vol_ma"] = g["volume"].rolling(20).mean()
g["macd_norm"] = (g["ema12"] - g["ema26"]) / g["close"]
g["ema_gap"] = (g["ema12"] - g["ema26"]) / g["close"]
vol_mean = g["volume"].rolling(20).mean()
vol_std = g["volume"].rolling(20).std()
g["vol_ratio"] = g["volume"] / vol_mean.replace(0, 1e-9)
g["vol_z"] = (g["volume"] - vol_mean) / vol_std.replace(0, 1e-9)
g["bar_range_pct"] = (g["high"] - g["low"]) / g["close"]
g["hl_pos"] = (g["close"] - g["low"]) / (g["high"] - g["low"]).replace(0, 1e-9)
last = g.dropna().iloc[-1]
try:
return [float(last[c]) for c in DEFAULT_FEATURES]
Expand Down Expand Up @@ -130,11 +158,17 @@ def predict_all(self, symbols: Optional[list[str]] = None) -> list[dict]:
"""Прогноз по всем активам, для которых есть данные."""
if not self.available:
return [{"ok": False, "error": "Модель не обучена. Запустите Colab-ноутбук Quant ML Training."}]
# Мёртвые/переименованные тикеры (MATIC->POL, RNDR->RENDER): старые
# папки данных остаются, но в сигналы не включаются.
dead = {"MATIC", "RNDR"}
if symbols is None:
symbols = sorted(d.name for d in QUANT_DIR.iterdir()
if d.is_dir() and not d.name.startswith("_") and d.name not in ("export", "models", "uniswap_v3"))
if d.is_dir() and not d.name.startswith("_")
and d.name not in ("export", "models", "uniswap_v3", *dead))
out = []
for s in symbols:
if s in dead:
continue
r = self.predict_symbol(s)
if r.get("ok"):
out.append(r)
Expand Down
52 changes: 39 additions & 13 deletions aios_core/quant/rl_signal_bridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,23 @@
from typing import Optional

REPO_ROOT = Path(__file__).resolve().parents[2]
MODEL_FILE = REPO_ROOT / "data" / "quant" / "models" / "ppo_v8.pt" # лучшая LSTM-PPO (300 эп, +75.23%)
MODEL_FILE = REPO_ROOT / "data" / "quant" / "models" / "ppo_v9.pt" # LSTM-PPO v9 (300 эп, sum_rl +96% vs BH −114%)
OUT_FILE = REPO_ROOT / "data" / "quant" / "rl_signals.json"

LOG_TAG = "[RLSignalBridge]"

# 32 актива среды обучения (quant_train_ppo.py, MultiAssetEnv):
# self.names = sorted(assets.keys()) — onehot-индекс актива в этом порядке.
# Используется как fallback; предпочтительно читать assets из чекпоинта
# модели (ppo_v9.pt сохраняет {"policy", "assets"}), т.к. v8 обучалась с
# MATIC, а v9 — с POL (разные индексы в onehot).
ASSET_ORDER_DEFAULT = sorted([
"BTC", "ETH", "BNB", "SOL", "XRP", "ADA", "DOGE", "AVAX", "LINK", "DOT",
"POL", "LTC", "TRX", "ATOM", "UNI", "ETC", "FIL", "APT", "NEAR", "ARB",
"OP", "SUI", "TIA", "SEI", "TON", "INJ", "KAS", "FET", "WIF", "BONK",
"PEPE", "SHIB",
])


class RLSignalBridge:
"""Консультирующий доступ к RL-сигналам (read-only)."""
Expand All @@ -33,6 +45,7 @@ def __init__(self, model_file: Optional[Path] = None):
self.model_file = Path(model_file or MODEL_FILE)
self._policy = None
self._model_available = self.model_file.exists()
self.asset_names = ASSET_ORDER_DEFAULT

# ---- модель ----
def _load_policy(self):
Expand Down Expand Up @@ -83,6 +96,7 @@ def forward(self, x):

ckpt = torch.load(self.model_file, map_location="cpu")
sd = ckpt.get("policy", ckpt)
self.asset_names = sorted(ckpt.get("assets") or ASSET_ORDER_DEFAULT)
# определяем архитектуру по наличию lstm-слоя
if "lstm.weight_ih_l0" in sd:
w = sd["fc_pre.weight"]
Expand Down Expand Up @@ -124,7 +138,7 @@ def _fetch_binance(self, sym: str, interval: str = "1h", limit: int = 120) -> li
d = json.loads(r.read())
return [[int(x[0]), float(x[1]), float(x[2]), float(x[3]), float(x[4]), float(x[5])] for x in d]

def _make_obs(self, rows: list, window: int = 10) -> Optional[list]:
def _make_obs(self, rows: list, asset_name: Optional[str] = None, window: int = 10) -> Optional[list]:
import numpy as np
if len(rows) < window + 1:
return None
Expand All @@ -140,10 +154,14 @@ def mom(period):
m[i] = closes[i] / closes[i - period] - 1.0
return m
mom5 = mom(5); mom12 = mom(12)
vol_chg = [0.0] * n
for i in range(1, n):
vol_chg[i] = vols[i] / vols[i - 1] - 1.0 if vols[i-1] else 0.0
# волатильность
# vol_ratio: volume / rolling(10)-mean — признак #3 среды обучения v8.
# (Раньше здесь был vol_chg — несоответствие обучению: модель видела
# другой 3-й статический признак.)
vol_ratio = [0.0] * n
for i in range(n):
lo = max(0, i - 9)
vol_ratio[i] = vols[i] / ((sum(vols[lo:i + 1]) / (i - lo + 1)) + 1e-9)
# vol_norm: rolling(10) std возвратов / среднее по ряду
vol_arr = [0.01]*n
for i in range(1, n):
w = returns[max(0,i-10):i]
Expand All @@ -153,37 +171,45 @@ def mom(period):
last = n - 1
base = np.concatenate([
rets_w,
[mom5[last], mom12[last], vol_chg[last], vol_arr[last]/vmean]
[mom5[last], mom12[last], vol_ratio[last], vol_arr[last]/vmean]
]).astype(np.float32)
exp = self._obs_dim
if base.shape[0] == exp:
return base
# мультиактив-модель: base (window+4) + onehot (n_assets)
if exp > base.shape[0]:
n_assets = exp - base.shape[0]
asset_names = getattr(self, "asset_names", ASSET_ORDER_DEFAULT)
if asset_name is None or asset_name not in asset_names:
# Актив не из обучающего универсума — честно сообщаем «нет сигнала»
# вместо того, чтобы подставлять чужой onehot-индекс.
return None
onehot = np.zeros(n_assets, dtype=np.float32)
# предполагаем BTC как индекс 0 (первый актив)
onehot[0] = 1.0
onehot[asset_names.index(asset_name)] = 1.0
obs = np.concatenate([base, onehot]).astype(np.float32)
if obs.shape[0] == exp:
return obs
return None

# ---- предсказание ----
def predict_symbol(self, binance_symbol: str) -> Optional[dict]:
def predict_symbol(self, binance_symbol: str, asset_name: Optional[str] = None) -> Optional[dict]:
policy = self._load_policy()
if policy is None:
return None
try:
rows = self._fetch_binance(binance_symbol)
obs = self._make_obs(rows)
obs = self._make_obs(rows, asset_name)
if obs is None:
return None
import torch
with torch.no_grad():
o_t = torch.tensor(obs, dtype=torch.float32).unsqueeze(0)
mean, _, _ = policy(o_t)
act = mean[0][0].item()
# В обучении (kg_v8) действие clamp(-1,1) до конвертации в
# дискрету {0,1,2}; без clamp mean может выйти за [-1,1] и дать
# недопустимую позицию (например, -0.5).
act = max(-1.0, min(1.0, act))
pos = int((act + 1) / 2 * 2) / 2.0 # 0, 0.5, 1
return {
"symbol": binance_symbol,
Expand All @@ -204,12 +230,12 @@ def run_all(self, symbols: Optional[dict] = None) -> dict:
symbols = {
"BTC": "BTCUSDT", "ETH": "ETHUSDT", "SOL": "SOLUSDT", "BNB": "BNBUSDT",
"XRP": "XRPUSDT", "ADA": "ADAUSDT", "DOGE": "DOGEUSDT", "LINK": "LINKUSDT",
"DOT": "DOTUSDT", "MATIC": "MATICUSDT",
"DOT": "DOTUSDT", "POL": "POLUSDT",
}
signals = []
for name, sym in symbols.items():
try:
res = self.predict_symbol(sym)
res = self.predict_symbol(sym, asset_name=name)
if res:
res["asset"] = name
signals.append(res)
Expand Down
6 changes: 6 additions & 0 deletions aios_core/quant_directional_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ class DirectionalV2Config:
half_spread_rate: float = 0.0005
slippage_rate: float = 0.0005
candle_seconds: int = 3_600
take_profit_pct: float = 0.02
stop_loss_pct: float = -0.01
trail_ratio: float = 0.988

@classmethod
def from_env(cls) -> DirectionalV2Config:
Expand All @@ -57,6 +60,9 @@ def from_env(cls) -> DirectionalV2Config:
half_spread_rate=max(0.0, float(os.environ.get("AIOS_QUANT_HALF_SPREAD_RATE", "0.0005"))),
slippage_rate=max(0.0, float(os.environ.get("AIOS_QUANT_SLIPPAGE_RATE", "0.0005"))),
candle_seconds=max(60, int(os.environ.get("AIOS_QUANT_CANDLE_SECONDS", "3600"))),
take_profit_pct=max(0.0, float(os.environ.get("AIOS_QUANT_TAKE_PROFIT_PCT", "0.02"))),
stop_loss_pct=min(0.0, float(os.environ.get("AIOS_QUANT_STOP_LOSS_PCT", "-0.01"))),
trail_ratio=min(1.0, max(0.0, float(os.environ.get("AIOS_QUANT_TRAIL_RATIO", "0.988")))),
)

def entry_execution_price(self, mid_price: float) -> float:
Expand Down
6 changes: 3 additions & 3 deletions aios_core/quant_directional_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,11 @@ def run_multi_exchange_cycle(engine) -> dict[str, Any]:
held_seconds = max(0.0, now - float(position.get("opened_at", now)))

reason = ""
if net_pnl_pct >= 2.0:
if net_pnl_pct >= config.take_profit_pct * 100.0:
reason = "take_profit"
elif net_pnl_pct <= -1.0:
elif net_pnl_pct <= config.stop_loss_pct * 100.0:
reason = "stop_loss"
elif max_seen > entry_mid * 1.01 and mid_price <= max_seen * 0.988:
elif max_seen > entry_mid * 1.01 and mid_price <= max_seen * config.trail_ratio:
reason = "trailing_stop"
elif bearish_exit_confirmed(config, analysis, held_seconds=held_seconds):
reason = "confirmed_bearish_exit"
Expand Down
Loading
Loading