GARCH Forecast Curve — The Pressure Reservoir
Imagine market volatility as pressure inside a reservoir. Some pressure comes from the reservoir's persistent background state, while some comes from recent disturbances. The important feature is not simply whether pressure is high or low, but how the expected pressure changes as the observer looks farther into the future.

The program starts with an older estimate of typical squared return activity. It then replays completed returns through a stationary GARCH update. Recent squared returns contribute fresh disturbance, while the preceding conditional variance supplies memory. A smaller background contribution prevents the estimate from relying entirely on the latest event or on an indefinitely persistent initial condition.

The update coefficients are fixed assumptions in this implementation. They are not repeatedly fitted to maximize historical likelihood. Once the current conditional state has been estimated, the program projects a sequence of future variance readings. These forecasts gradually move toward the background level, creating a volatility forecast curve across several future horizons.

The strategy seeks a particular reservoir shape: near future pressure must be noticeably lower than pressure farther along the curve. This is interpreted as compression rather than as immediate danger. A new completed return must then show a meaningful release relative to the conditional scale, but not an extremely violent jump beyond the program's accepted range.

Direction requires agreement with an earlier trend measure. An upward release is considered for buying only when the preceding broader movement is also upward. The corresponding downward agreement supports selling. A release that contradicts the background directional picture does not receive the same instruction merely because its magnitude is large.

Positions can be closed when conditional risk becomes substantially elevated relative to the estimated background. That exit reflects the distinction between entering a controlled release and remaining exposed after the reservoir has become highly disturbed. Protective stops use a selected forecast variance, and profit targets and holding limits provide additional boundaries.

The diagnostic layer reports aggregated forecast uncertainty, a historical Gaussian scoring measure, and the projected variance path after a hypothetical standardized shock. These outputs make the persistence assumptions visible and help show how quickly the model expects disturbances to decay.

The reservoir is only a model. Financial returns can have heavy tails, changing parameters, and abrupt structural breaks that fixed stationary coefficients do not capture. A forecast curve that slopes upward is not a direct forecast of price direction. The trading interpretation combines a volatility condition with a separate directional hypothesis, and both require out of sample evaluation before any claim of practical usefulness.

Code
// Independent model 07: GARCH variance forecast curve and compression release.
#include <default.c>

var GPrices[100];
var GForecast[16];
var GUnconditional = 0.;
var GConditional = 0.;
var GRelease = 0.;

int GProjectRisk()
{
    int T, Ahead;
    var R, Omega, State, Average, Current, Drift;
    GRelease = 0.;
    GConditional = 0.;
    GUnconditional = 0.;
    for (T = 0; T < 100; T++)
    {
        if (!(GPrices[T] > 0.))
        {
            return 0;
        }
    }
    Average = 0.;
    for (T = 1; T <= 80; T++)
    {
        R = log(GPrices[T] / GPrices[T + 1]);
        Average += R * R / 80.;
    }
    if (Average < 1.e-20)
    {
        return 0;
    }
    // Fixed stationary coefficients: alpha=.12, beta=.86, alpha+beta=.98.
    // These are model assumptions, NOT maximum-likelihood fitted parameters.
    GUnconditional = Average;
    Omega = Average * 0.02;
    State = Average;
    for (T = 80; T >= 1; T--)
    {
        R = log(GPrices[T] / GPrices[T + 1]);
        State = Omega + 0.12 * R * R + 0.86 * State;
    }
    GConditional = State;
    for (Ahead = 0; Ahead < 16; Ahead++)
    {
        GForecast[Ahead] = Average + pow(0.98, Ahead) * (State - Average);
    }
    // Term-structure slope must indicate low immediate risk versus distant risk.
    if (GForecast[0] >= 0.8 * GForecast[15])
    {
        return 0;
    }
    Current = log(GPrices[0] / GPrices[1]);
    Drift = log(GPrices[1] / GPrices[17]);
    GRelease = Current / sqrt(State);
    if (abs(GRelease) < 1.5 || abs(GRelease) > 4.)
    {
        return 0;
    }
    if (Current > 0. && Drift > 0.)
    {
        return 1;
    }
    if (Current < 0. && Drift < 0.)
    {
        return -1;
    }
    return 0;
}

void GExamine()
{
    int T, A, B, F;
    F = 0;
    for (T = 0; T < 100; T++)
    {
        GPrices[T] = 1.;
    }
    if (GProjectRisk() != 0)
    {
        F++;
    }
    for (T = 0; T < 100; T++)
    {
        GPrices[T] = exp(0.001 * cos(0.31 * T));
    }
    A = GProjectRisk();
    if (GConditional <= 0. || GForecast[15] <= 0.)
    {
        F++;
    }
    for (T = 0; T < 100; T++)
    {
        GPrices[T] = 1. / GPrices[T];
    }
    B = GProjectRisk();
    if (A != -B)
    {
        F++;
    }
    GPrices[4] = 0.;
    if (GProjectRisk() != 0)
    {
        F++;
    }
    file_write("Log/TS07_GARCHForecastCurve_test.txt", strf("4 checks; %d failures\n", F), 0);
}

var GIntegratedForecast(int Horizon)
{
    int Ahead;
    var Sum;
    Sum = 0.;
    if (Horizon < 1 || Horizon > 16)
    {
        return 0.;
    }
    for (Ahead = 0; Ahead < Horizon; Ahead++)
    {
        Sum += GForecast[Ahead];
    }
    return sqrt(max(0., Sum));
}
var GGaussianScore()
{
    int T;
    var R, V, LogScore;
    if (GUnconditional <= 0.)
    {
        return 0.;
    }
    V = GUnconditional;
    LogScore = 0.;
    for (T = 64; T >= 1; T--)
    {
        R = log(GPrices[T] / GPrices[T + 1]);
        LogScore += log(max(V, 1.e-25)) + R * R / max(V, 1.e-25);
        V = 0.02 * GUnconditional + 0.12 * R * R + 0.86 * V;
    }
    return -LogScore / 128.;
}
var GVarianceAfterShock(var ShockSigma, int Steps)
{
    int Step;
    var V;
    if (Steps < 1 || Steps > 64 || GConditional <= 0.)
    {
        return 0.;
    }
    V = 0.02 * GUnconditional + (0.12 * ShockSigma * ShockSigma + 0.86) * GConditional;
    for (Step = 1; Step < Steps; Step++)
    {
        V = 0.02 * GUnconditional + 0.98 * V;
    }
    return V;
}
void GResearchDiagnostics()
{
    printf("\nGARCH forecast sigma4 %.6g; sigma16 %.6g; log-score %.6g; postshock variance %.6g",
           GIntegratedForecast(4), GIntegratedForecast(16), GGaussianScore(),
           GVarianceAfterShock(3., 4));
}

// ============================================================================
// EXTENDED REGRESSION SUITE: deterministic properties over market regimes
// These functions run ONLY under STX_SELFTEST; they never place orders.
// ============================================================================
int GExtendedCount = 0;
int GExtendedFailures = 0;
void GExpect(int Passed, string Description)
{
    GExtendedCount++;
    if (!Passed)
    {
        GExtendedFailures++;
        file_append("Log/TS07_GARCHForecastCurve_extended.txt", strf("FAIL: %s\n", Description));
    }
}

void GCase_quiet_cycle()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1.0 * exp(0.0005 * sin(0.17 * K));
    }
    Original = GProjectRisk();
    GExpect(Original >= -1 && Original <= 1, "quiet_cycle: bounded direction");
    Again = GProjectRisk();
    GExpect(Again == Original, "quiet_cycle: repeatable estimate");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] *= 7.;
    }
    Scaled = GProjectRisk();
    GExpect(Scaled == Original, "quiet_cycle: price-unit invariance");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1. / GPrices[K];
    }
    Reflected = GProjectRisk();
    GExpect(Reflected == -Original, "quiet_cycle: directional reflection");
    GPrices[50] = 0.;
    GExpect(GProjectRisk() == 0, "quiet_cycle: missing price rejected");
}

void GCase_mixed_cycles()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1.0 * exp(0.003 * sin(0.23 * K) + 0.0007 * cos(0.81 * K));
    }
    Original = GProjectRisk();
    GExpect(Original >= -1 && Original <= 1, "mixed_cycles: bounded direction");
    Again = GProjectRisk();
    GExpect(Again == Original, "mixed_cycles: repeatable estimate");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] *= 7.;
    }
    Scaled = GProjectRisk();
    GExpect(Scaled == Original, "mixed_cycles: price-unit invariance");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1. / GPrices[K];
    }
    Reflected = GProjectRisk();
    GExpect(Reflected == -Original, "mixed_cycles: directional reflection");
    GPrices[50] = 0.;
    GExpect(GProjectRisk() == 0, "mixed_cycles: missing price rejected");
}

void GCase_persistent_upward()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1.0 * exp(-0.001 * K + 0.0001 * sin(0.53 * K));
    }
    Original = GProjectRisk();
    GExpect(Original >= -1 && Original <= 1, "persistent_upward: bounded direction");
    Again = GProjectRisk();
    GExpect(Again == Original, "persistent_upward: repeatable estimate");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] *= 7.;
    }
    Scaled = GProjectRisk();
    GExpect(Scaled == Original, "persistent_upward: price-unit invariance");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1. / GPrices[K];
    }
    Reflected = GProjectRisk();
    GExpect(Reflected == -Original, "persistent_upward: directional reflection");
    GPrices[50] = 0.;
    GExpect(GProjectRisk() == 0, "persistent_upward: missing price rejected");
}

void GCase_persistent_downward()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1.0 * exp(0.001 * K + 0.0001 * cos(0.47 * K));
    }
    Original = GProjectRisk();
    GExpect(Original >= -1 && Original <= 1, "persistent_downward: bounded direction");
    Again = GProjectRisk();
    GExpect(Again == Original, "persistent_downward: repeatable estimate");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] *= 7.;
    }
    Scaled = GProjectRisk();
    GExpect(Scaled == Original, "persistent_downward: price-unit invariance");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1. / GPrices[K];
    }
    Reflected = GProjectRisk();
    GExpect(Reflected == -Original, "persistent_downward: directional reflection");
    GPrices[50] = 0.;
    GExpect(GProjectRisk() == 0, "persistent_downward: missing price rejected");
}

void GCase_slow_curve()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1.0 * exp(0.004 * cos(0.08 * K) + 0.0002 * sin(0.7 * K));
    }
    Original = GProjectRisk();
    GExpect(Original >= -1 && Original <= 1, "slow_curve: bounded direction");
    Again = GProjectRisk();
    GExpect(Again == Original, "slow_curve: repeatable estimate");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] *= 7.;
    }
    Scaled = GProjectRisk();
    GExpect(Scaled == Original, "slow_curve: price-unit invariance");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1. / GPrices[K];
    }
    Reflected = GProjectRisk();
    GExpect(Reflected == -Original, "slow_curve: directional reflection");
    GPrices[50] = 0.;
    GExpect(GProjectRisk() == 0, "slow_curve: missing price rejected");
}

void GCase_rough_curve()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1.0 * exp(0.001 * sin(1.7 * K) + 0.0005 * cos(2.3 * K));
    }
    Original = GProjectRisk();
    GExpect(Original >= -1 && Original <= 1, "rough_curve: bounded direction");
    Again = GProjectRisk();
    GExpect(Again == Original, "rough_curve: repeatable estimate");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] *= 7.;
    }
    Scaled = GProjectRisk();
    GExpect(Scaled == Original, "rough_curve: price-unit invariance");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1. / GPrices[K];
    }
    Reflected = GProjectRisk();
    GExpect(Reflected == -Original, "rough_curve: directional reflection");
    GPrices[50] = 0.;
    GExpect(GProjectRisk() == 0, "rough_curve: missing price rejected");
}

void GCase_accelerating_path()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1.0 * exp(-0.0001 * K - 0.000002 * K * K + 0.0002 * sin(0.41 * K));
    }
    Original = GProjectRisk();
    GExpect(Original >= -1 && Original <= 1, "accelerating_path: bounded direction");
    Again = GProjectRisk();
    GExpect(Again == Original, "accelerating_path: repeatable estimate");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] *= 7.;
    }
    Scaled = GProjectRisk();
    GExpect(Scaled == Original, "accelerating_path: price-unit invariance");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1. / GPrices[K];
    }
    Reflected = GProjectRisk();
    GExpect(Reflected == -Original, "accelerating_path: directional reflection");
    GPrices[50] = 0.;
    GExpect(GProjectRisk() == 0, "accelerating_path: missing price rejected");
}

void GCase_decelerating_path()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1.0 * exp(-0.0008 * K + 0.000002 * K * K + 0.0002 * cos(0.31 * K));
    }
    Original = GProjectRisk();
    GExpect(Original >= -1 && Original <= 1, "decelerating_path: bounded direction");
    Again = GProjectRisk();
    GExpect(Again == Original, "decelerating_path: repeatable estimate");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] *= 7.;
    }
    Scaled = GProjectRisk();
    GExpect(Scaled == Original, "decelerating_path: price-unit invariance");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1. / GPrices[K];
    }
    Reflected = GProjectRisk();
    GExpect(Reflected == -Original, "decelerating_path: directional reflection");
    GPrices[50] = 0.;
    GExpect(GProjectRisk() == 0, "decelerating_path: missing price rejected");
}

void GCase_volatility_ramp()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1.0 * exp((0.0001 + K * 0.00001) * sin(0.37 * K));
    }
    Original = GProjectRisk();
    GExpect(Original >= -1 && Original <= 1, "volatility_ramp: bounded direction");
    Again = GProjectRisk();
    GExpect(Again == Original, "volatility_ramp: repeatable estimate");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] *= 7.;
    }
    Scaled = GProjectRisk();
    GExpect(Scaled == Original, "volatility_ramp: price-unit invariance");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1. / GPrices[K];
    }
    Reflected = GProjectRisk();
    GExpect(Reflected == -Original, "volatility_ramp: directional reflection");
    GPrices[50] = 0.;
    GExpect(GProjectRisk() == 0, "volatility_ramp: missing price rejected");
}

void GCase_volatility_decay()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1.0 * exp(0.006 * exp(-0.02 * K) * cos(0.7 * K));
    }
    Original = GProjectRisk();
    GExpect(Original >= -1 && Original <= 1, "volatility_decay: bounded direction");
    Again = GProjectRisk();
    GExpect(Again == Original, "volatility_decay: repeatable estimate");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] *= 7.;
    }
    Scaled = GProjectRisk();
    GExpect(Scaled == Original, "volatility_decay: price-unit invariance");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1. / GPrices[K];
    }
    Reflected = GProjectRisk();
    GExpect(Reflected == -Original, "volatility_decay: directional reflection");
    GPrices[50] = 0.;
    GExpect(GProjectRisk() == 0, "volatility_decay: missing price rejected");
}

void GCase_cycle_with_drift()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1.0 * exp(-0.0002 * K + 0.003 * sin(0.19 * K) + 0.0005 * cos(0.61 * K));
    }
    Original = GProjectRisk();
    GExpect(Original >= -1 && Original <= 1, "cycle_with_drift: bounded direction");
    Again = GProjectRisk();
    GExpect(Again == Original, "cycle_with_drift: repeatable estimate");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] *= 7.;
    }
    Scaled = GProjectRisk();
    GExpect(Scaled == Original, "cycle_with_drift: price-unit invariance");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1. / GPrices[K];
    }
    Reflected = GProjectRisk();
    GExpect(Reflected == -Original, "cycle_with_drift: directional reflection");
    GPrices[50] = 0.;
    GExpect(GProjectRisk() == 0, "cycle_with_drift: missing price rejected");
}

void GCase_near_zero_prices()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 0.0001 * exp(0.002 * sin(0.29 * K) + 0.001 * cos(0.13 * K));
    }
    Original = GProjectRisk();
    GExpect(Original >= -1 && Original <= 1, "near_zero_prices: bounded direction");
    Again = GProjectRisk();
    GExpect(Again == Original, "near_zero_prices: repeatable estimate");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] *= 7.;
    }
    Scaled = GProjectRisk();
    GExpect(Scaled == Original, "near_zero_prices: price-unit invariance");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1. / GPrices[K];
    }
    Reflected = GProjectRisk();
    GExpect(Reflected == -Original, "near_zero_prices: directional reflection");
    GPrices[50] = 0.;
    GExpect(GProjectRisk() == 0, "near_zero_prices: missing price rejected");
}

void GCase_large_price_units()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 10000.0 * exp(0.003 * sin(0.11 * K) + 0.0008 * cos(0.43 * K));
    }
    Original = GProjectRisk();
    GExpect(Original >= -1 && Original <= 1, "large_price_units: bounded direction");
    Again = GProjectRisk();
    GExpect(Again == Original, "large_price_units: repeatable estimate");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] *= 7.;
    }
    Scaled = GProjectRisk();
    GExpect(Scaled == Original, "large_price_units: price-unit invariance");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1. / GPrices[K];
    }
    Reflected = GProjectRisk();
    GExpect(Reflected == -Original, "large_price_units: directional reflection");
    GPrices[50] = 0.;
    GExpect(GProjectRisk() == 0, "large_price_units: missing price rejected");
}

void GCase_high_frequency_chop()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1.0 * exp(0.0008 * cos(2.8 * K) + 0.001 * sin(0.23 * K));
    }
    Original = GProjectRisk();
    GExpect(Original >= -1 && Original <= 1, "high_frequency_chop: bounded direction");
    Again = GProjectRisk();
    GExpect(Again == Original, "high_frequency_chop: repeatable estimate");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] *= 7.;
    }
    Scaled = GProjectRisk();
    GExpect(Scaled == Original, "high_frequency_chop: price-unit invariance");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1. / GPrices[K];
    }
    Reflected = GProjectRisk();
    GExpect(Reflected == -Original, "high_frequency_chop: directional reflection");
    GPrices[50] = 0.;
    GExpect(GProjectRisk() == 0, "high_frequency_chop: missing price rejected");
}

void GCase_long_wave_trend()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1.0 * exp(-0.0005 * K + 0.002 * cos(0.07 * K));
    }
    Original = GProjectRisk();
    GExpect(Original >= -1 && Original <= 1, "long_wave_trend: bounded direction");
    Again = GProjectRisk();
    GExpect(Again == Original, "long_wave_trend: repeatable estimate");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] *= 7.;
    }
    Scaled = GProjectRisk();
    GExpect(Scaled == Original, "long_wave_trend: price-unit invariance");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1. / GPrices[K];
    }
    Reflected = GProjectRisk();
    GExpect(Reflected == -Original, "long_wave_trend: directional reflection");
    GPrices[50] = 0.;
    GExpect(GProjectRisk() == 0, "long_wave_trend: missing price rejected");
}

void GCase_opposing_scales()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1.0 * exp(0.005 * sin(0.09 * K) - 0.002 * sin(0.59 * K));
    }
    Original = GProjectRisk();
    GExpect(Original >= -1 && Original <= 1, "opposing_scales: bounded direction");
    Again = GProjectRisk();
    GExpect(Again == Original, "opposing_scales: repeatable estimate");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] *= 7.;
    }
    Scaled = GProjectRisk();
    GExpect(Scaled == Original, "opposing_scales: price-unit invariance");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1. / GPrices[K];
    }
    Reflected = GProjectRisk();
    GExpect(Reflected == -Original, "opposing_scales: directional reflection");
    GPrices[50] = 0.;
    GExpect(GProjectRisk() == 0, "opposing_scales: missing price rejected");
}

void GCase_nonlinear_curve()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1.0 * exp(0.002 * sin(0.021 * K * K) + 0.001 * cos(0.33 * K));
    }
    Original = GProjectRisk();
    GExpect(Original >= -1 && Original <= 1, "nonlinear_curve: bounded direction");
    Again = GProjectRisk();
    GExpect(Again == Original, "nonlinear_curve: repeatable estimate");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] *= 7.;
    }
    Scaled = GProjectRisk();
    GExpect(Scaled == Original, "nonlinear_curve: price-unit invariance");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1. / GPrices[K];
    }
    Reflected = GProjectRisk();
    GExpect(Reflected == -Original, "nonlinear_curve: directional reflection");
    GPrices[50] = 0.;
    GExpect(GProjectRisk() == 0, "nonlinear_curve: missing price rejected");
}

void GCase_amplitude_modulation()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1.0 * exp(0.002 * sin(0.3 * K) * cos(0.04 * K));
    }
    Original = GProjectRisk();
    GExpect(Original >= -1 && Original <= 1, "amplitude_modulation: bounded direction");
    Again = GProjectRisk();
    GExpect(Again == Original, "amplitude_modulation: repeatable estimate");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] *= 7.;
    }
    Scaled = GProjectRisk();
    GExpect(Scaled == Original, "amplitude_modulation: price-unit invariance");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1. / GPrices[K];
    }
    Reflected = GProjectRisk();
    GExpect(Reflected == -Original, "amplitude_modulation: directional reflection");
    GPrices[50] = 0.;
    GExpect(GProjectRisk() == 0, "amplitude_modulation: missing price rejected");
}

void GCase_decaying_event()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1.0 * exp(0.01 * exp(-0.2 * K) + 0.0003 * sin(0.71 * K));
    }
    Original = GProjectRisk();
    GExpect(Original >= -1 && Original <= 1, "decaying_event: bounded direction");
    Again = GProjectRisk();
    GExpect(Again == Original, "decaying_event: repeatable estimate");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] *= 7.;
    }
    Scaled = GProjectRisk();
    GExpect(Scaled == Original, "decaying_event: price-unit invariance");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1. / GPrices[K];
    }
    Reflected = GProjectRisk();
    GExpect(Reflected == -Original, "decaying_event: directional reflection");
    GPrices[50] = 0.;
    GExpect(GProjectRisk() == 0, "decaying_event: missing price rejected");
}

void GCase_time_varying_frequency()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1.0 * exp(0.002 * cos(0.004 * K * K + 0.11 * K));
    }
    Original = GProjectRisk();
    GExpect(Original >= -1 && Original <= 1, "time_varying_frequency: bounded direction");
    Again = GProjectRisk();
    GExpect(Again == Original, "time_varying_frequency: repeatable estimate");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] *= 7.;
    }
    Scaled = GProjectRisk();
    GExpect(Scaled == Original, "time_varying_frequency: price-unit invariance");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1. / GPrices[K];
    }
    Reflected = GProjectRisk();
    GExpect(Reflected == -Original, "time_varying_frequency: directional reflection");
    GPrices[50] = 0.;
    GExpect(GProjectRisk() == 0, "time_varying_frequency: missing price rejected");
}

void GCase_slow_fast_cancellation()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1.0 * exp(0.004 * sin(0.07 * K) + 0.0013 * cos(0.97 * K));
    }
    Original = GProjectRisk();
    GExpect(Original >= -1 && Original <= 1, "slow_fast_cancellation: bounded direction");
    Again = GProjectRisk();
    GExpect(Again == Original, "slow_fast_cancellation: repeatable estimate");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] *= 7.;
    }
    Scaled = GProjectRisk();
    GExpect(Scaled == Original, "slow_fast_cancellation: price-unit invariance");
    for (K = 0; K < 100; K++)
    {
        GPrices[K] = 1. / GPrices[K];
    }
    Reflected = GProjectRisk();
    GExpect(Reflected == -Original, "slow_fast_cancellation: directional reflection");
    GPrices[50] = 0.;
    GExpect(GProjectRisk() == 0, "slow_fast_cancellation: missing price rejected");
}

void GExtendedTests()
{
    GExtendedCount = 0;
    GExtendedFailures = 0;
    file_write("Log/TS07_GARCHForecastCurve_extended.txt",
               "TS07_GARCHForecastCurve: extended properties\n", 0);
    GCase_quiet_cycle();
    GCase_mixed_cycles();
    GCase_persistent_upward();
    GCase_persistent_downward();
    GCase_slow_curve();
    GCase_rough_curve();
    GCase_accelerating_path();
    GCase_decelerating_path();
    GCase_volatility_ramp();
    GCase_volatility_decay();
    GCase_cycle_with_drift();
    GCase_near_zero_prices();
    GCase_large_price_units();
    GCase_high_frequency_chop();
    GCase_long_wave_trend();
    GCase_opposing_scales();
    GCase_nonlinear_curve();
    GCase_amplitude_modulation();
    GCase_decaying_event();
    GCase_time_varying_frequency();
    GCase_slow_fast_cancellation();
    file_append("Log/TS07_GARCHForecastCurve_extended.txt",
                strf("RESULT: %d checks; %d failures\n", GExtendedCount, GExtendedFailures));
}

function run()
{
#ifdef STX_SELFTEST
    if (is(INITRUN))
    {
        GExamine();
        GExtendedTests();
        quit("GARCH tests complete");
    }
    return;
#endif
    int T, Expansion;
    var SizeLimit, Damage;
    BarPeriod = 60;
    LookBack = 101;
    StartDate = 20240101;
    EndDate = 20241231;
    Capital = 10000.;
    MaxLong = 1;
    MaxShort = 1;
    Hedge = 0;
    if (!asset("EUR/USD"))
    {
        return;
    }
    algo("G07");
    if (is(EXITRUN))
    {
        GResearchDiagnostics();
        return;
    }
    if (is(LOOKBACK))
    {
        return;
    }
    for (T = 0; T < 100; T++)
    {
        GPrices[T] = priceClose(T + 1);
    }
    Expansion = GProjectRisk();
    // Exit after the predicted compression has become an elevated-risk regime.
    if (GUnconditional > 0. && GConditional > 1.8 * GUnconditional)
    {
        exitLong();
        exitShort();
    }
    if (Expansion == 0 || NumOpenLong + NumOpenShort > 0)
    {
        return;
    }
    if (Balance <= 0. || Equity < Balance * 0.85)
    {
        return;
    }
    if (PIP <= 0. || PIPCost <= 0. || LotAmount <= 0. || MarginCost <= 0.)
    {
        return;
    }
    Stop = max(30. * PIP, GPrices[0] * sqrt(GForecast[3]) * 2.5);
    TakeProfit = Stop * 3.;
    LifeTime = 20;
    Damage = (Stop + Spread) / PIP * PIPCost + Commission * LotAmount / 10000.;
    if (Damage <= 0.)
    {
        return;
    }
    SizeLimit = min(Balance * 0.005 / Damage, 2000. / LotAmount);
    SizeLimit = min(SizeLimit, max(0., Equity - MarginVal) * 0.8 / MarginCost);
    if (SizeLimit < 1.)
    {
        return;
    }
    Risk = 0.;
    Margin = 0.;
    Lots = floor(SizeLimit);
    if (Expansion > 0)
    {
        enterLong();
    }
    else
    {
        enterShort();
    }
}