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;
}