Spaces:
Sleeping
Sleeping
File size: 5,454 Bytes
d09916e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | /*
* 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;
}
|