Spaces:
Sleeping
Sleeping
| /* | |
| * force_exit_timer.cl | |
| * ───────────────────────────────────────────────────────────────────────────── | |
| * GPU Kernel: Time-Based Trade Force Exit | |
| * | |
| * Responsibility: | |
| * Evaluate three time-based exit conditions for each open position simultaneously. | |
| * This is the kill switch that overrides price-based reasoning when time expires. | |
| * | |
| * Rule 1 — Natural time cap: | |
| * elapsed_nat >= max_nat_s → exit | |
| * Hard stop. The cycle window has closed. No edge remains. | |
| * | |
| * Rule 2 — Price linger: | |
| * elapsed_nat >= LINGER_CHECK_S AND |price_move_pct| < LINGER_TOL | |
| * → exit (LINGER) | |
| * Price returned to entry zone without moving. Thesis invalidated quietly. | |
| * | |
| * Rule 3 — Synthetic budget exhausted: | |
| * elapsed_syn >= max_nat_s * vol_ratio * SYN_BUDGET_MUL → exit | |
| * Regime-adjusted version of Rule 1. Catches low-vol "stall" scenarios | |
| * where natural time passes slowly but market is information-dense. | |
| * | |
| * Inputs (global read): | |
| * elapsed_nat [M] float — natural seconds since entry per trade | |
| * elapsed_syn [M] float — synthetic seconds since entry per trade | |
| * price_move_pct [M] float — (current - entry) / entry signed | |
| * max_nat_s [M] float — per-trade natural time cap (seconds) | |
| * vol_ratio [1] float — current rolling_vol / baseline (from volclock) | |
| * is_open [M] int — 1 if trade is open, 0 if already closed | |
| * | |
| * Outputs (global write): | |
| * exit_flag [M] int — 1 = force close this trade | |
| * exit_reason [M] int — reason code: | |
| * 0 = HOLD | |
| * 1 = NATURAL_TIME_EXPIRED | |
| * 2 = PRICE_LINGER | |
| * 3 = SYNTHETIC_BUDGET | |
| * | |
| * Parameters (compile-time): | |
| * LINGER_CHECK_S — seconds before linger rule activates (default 30s) | |
| * LINGER_TOL — price move threshold to consider "lingering" (default 0.05%) | |
| * SYN_BUDGET_MUL — synthetic budget multiplier (default 1.0) | |
| * | |
| * Design notes: | |
| * • M = max concurrent open positions (e.g. 64 for single-instrument strategies). | |
| * • Fully parallel across M positions. No cross-item dependency. | |
| * • Rule priority: 1 > 2 > 3. First triggered rule wins. | |
| * • vol_ratio is a scalar broadcast (one value for current market regime). | |
| * ───────────────────────────────────────────────────────────────────────────── | |
| */ | |
| #ifndef LINGER_CHECK_S | |
| #define LINGER_CHECK_S 30.0f | |
| #endif | |
| #ifndef LINGER_TOL | |
| #define LINGER_TOL 0.0005f /* 5 basis points */ | |
| #endif | |
| #ifndef SYN_BUDGET_MUL | |
| #define SYN_BUDGET_MUL 1.0f | |
| #endif | |
| /* Exit reason codes */ | |
| #define REASON_HOLD 0 | |
| #define REASON_NATURAL_TIME_EXPIRED 1 | |
| #define REASON_PRICE_LINGER 2 | |
| #define REASON_SYNTHETIC_BUDGET 3 | |
| __kernel void force_exit_timer( | |
| __global const float* elapsed_nat, /* [M] natural seconds in trade */ | |
| __global const float* elapsed_syn, /* [M] synthetic seconds in trade */ | |
| __global const float* price_move_pct, /* [M] signed % move from entry */ | |
| __global const float* max_nat_s, /* [M] per-trade natural time cap */ | |
| __global const float* vol_ratio, /* [1] current vol / baseline scalar */ | |
| __global const int* is_open, /* [M] 1 = position open */ | |
| __global int* exit_flag, /* [M] OUT: 1 = close this trade */ | |
| __global int* exit_reason /* [M] OUT: reason code */ | |
| ) | |
| { | |
| int gid = get_global_id(0); | |
| /* Skip closed trades — write hold and return */ | |
| if (!is_open[gid]) { | |
| exit_flag[gid] = 0; | |
| exit_reason[gid] = REASON_HOLD; | |
| return; | |
| } | |
| float enat = elapsed_nat[gid]; | |
| float esyn = elapsed_syn[gid]; | |
| float move = fabs(price_move_pct[gid]); | |
| float mnat = max_nat_s[gid]; | |
| float vr = vol_ratio[0]; | |
| /* ── Rule 1: Natural time cap ──────────────────────────────────────── */ | |
| if (enat >= mnat) { | |
| exit_flag[gid] = 1; | |
| exit_reason[gid] = REASON_NATURAL_TIME_EXPIRED; | |
| return; | |
| } | |
| /* ── Rule 2: Price linger ───────────────────────────────────────────── */ | |
| if (enat >= LINGER_CHECK_S && move < LINGER_TOL) { | |
| exit_flag[gid] = 1; | |
| exit_reason[gid] = REASON_PRICE_LINGER; | |
| return; | |
| } | |
| /* ── Rule 3: Synthetic budget ───────────────────────────────────────── */ | |
| float syn_budget = mnat * vr * SYN_BUDGET_MUL; | |
| if (esyn >= syn_budget) { | |
| exit_flag[gid] = 1; | |
| exit_reason[gid] = REASON_SYNTHETIC_BUDGET; | |
| return; | |
| } | |
| /* ── No exit condition triggered ────────────────────────────────────── */ | |
| exit_flag[gid] = 0; | |
| exit_reason[gid] = REASON_HOLD; | |
| } | |