Covariance PCA — The Market Orchestra
Imagine the market as an orchestra whose instruments represent different ages of price movement. One instrument plays the latest change, another plays the preceding interval, and others represent progressively older stretches. These instruments come from the same Forex price history, but they do not simply repeat one identical return at different volumes. Each listens to a separate age bucket.

The program first examines how these instruments have moved together during recent completed bars. It builds a portrait of their shared activity. Exceptionally energetic observations can be excluded from this portrait so that one loud interruption does not completely dominate the arrangement. The result is an uncentered covariation portrait, which retains both directional movement and joint fluctuation rather than removing every average drift.

A numerical search then looks for the strongest common theme. Instead of decomposing the entire orchestra into every possible component, the program repeatedly refines one candidate direction. This process is called power iteration. Its purpose is to identify a principal direction explaining a substantial share of the observed activity. The program checks how dominant this theme is before considering a trade.

The newest completed observation is then projected onto that common theme. Crucially, the program translates the projection back toward the shortest price interval. This prevents an arbitrary reversal of the principal vector from reversing the economic meaning of the signal. The direction comes from observed movement interpreted through the component, not from the component's orientation alone.

When the common theme is sufficiently concentrated and its current projection is meaningfully positive, the strategy considers buying. A sufficiently negative projection supports selling. When the orchestra loses its common theme, existing positions can be closed. Positions also have protective stops, profit targets, and a maximum lifetime, so the component is not treated as permanent evidence.

Additional diagnostics examine the effective number of active directions, the concentration of component loadings, and the numerical residual of the estimated principal direction. These diagnostics help distinguish a coherent common movement from a poorly represented collection of unrelated fluctuations.

The orchestra remains an analogy, not a forecasting guarantee. Separate age buckets can still be statistically dependent, and a strong common component can describe movement that has already happened. Risk limits constrain individual exposure, but they do not establish that the common theme will continue after entry.

Code
// Independent model 01: robust cross-horizon covariance and power-iteration PCA.
// Forex horizon buckets are not bond maturities. Research prototype only.
#include <default.c>

string PCAAsset = "EUR/USD";
var PCAClose[150];
var PCAFeatures[320];
var PCAMatrix[25];
var PCAVector[5];
var PCAActivity = 0.;
var PCADominance = 0.;
int PCATenors[6] = {0, 1, 2, 4, 8, 16};

int PCAEvaluate()
{
    int Row, A, B, Iteration, Width;
    var Observation[5];
    var NextVector[5];
    var Trace, Energy, Limit, Projection, Eigenvalue, Norm;
    for (Row = 0; Row < 150; Row++)
    {
        if (!(PCAClose[Row] > 0.))
        {
            return 0;
        }
    }
    Energy = 0.;
    for (Row = 0; Row < 64; Row++)
    {
        for (A = 0; A < 5; A++)
        {
            Width = PCATenors[A + 1] - PCATenors[A];
            Projection =
                log(PCAClose[Row + 1 + PCATenors[A]] / PCAClose[Row + 1 + PCATenors[A + 1]]) /
                sqrt(Width);
            PCAFeatures[Row * 5 + A] = Projection;
            Energy += Projection * Projection / 64.;
        }
    }
    if (Energy <= 1.e-20)
    {
        return 0;
    }
    Limit = 9. * Energy;
    for (A = 0; A < 25; A++)
    {
        PCAMatrix[A] = 0.;
    }
    for (Row = 0; Row < 64; Row++)
    {
        Norm = 0.;
        for (A = 0; A < 5; A++)
        {
            Norm += PCAFeatures[Row * 5 + A] * PCAFeatures[Row * 5 + A];
        }
        if (Norm > Limit)
        {
            continue;
        }
        for (A = 0; A < 5; A++)
        {
            for (B = 0; B < 5; B++)
            {
                PCAMatrix[A * 5 + B] += PCAFeatures[Row * 5 + A] * PCAFeatures[Row * 5 + B] / 64.;
            }
        }
    }
    // Uncentered covariation preserves the drift direction in the observations.
    for (A = 0; A < 5; A++)
    {
        PCAVector[A] = 1. / sqrt(5.);
    }
    for (Iteration = 0; Iteration < 80; Iteration++)
    {
        Norm = 0.;
        for (A = 0; A < 5; A++)
        {
            NextVector[A] = 0.;
            for (B = 0; B < 5; B++)
            {
                NextVector[A] += PCAMatrix[A * 5 + B] * PCAVector[B];
            }
            Norm += NextVector[A] * NextVector[A];
        }
        if (Norm <= 1.e-40)
        {
            return 0;
        }
        for (A = 0; A < 5; A++)
        {
            PCAVector[A] = NextVector[A] / sqrt(Norm);
        }
    }
    Trace = 0.;
    Eigenvalue = 0.;
    Projection = 0.;
    for (A = 0; A < 5; A++)
    {
        Trace += PCAMatrix[A * 5 + A];
        for (B = 0; B < 5; B++)
        {
            Eigenvalue += PCAVector[A] * PCAMatrix[A * 5 + B] * PCAVector[B];
        }
        Width = PCATenors[A + 1] - PCATenors[A];
        Observation[A] = log(PCAClose[PCATenors[A]] / PCAClose[PCATenors[A + 1]]) / sqrt(Width);
        Projection += PCAVector[A] * Observation[A];
    }
    if (Trace <= 1.e-20)
    {
        return 0;
    }
    PCADominance = Eigenvalue / Trace;
    // Sign invariant: both vector factors change sign together.
    PCAActivity = Projection * PCAVector[0] / sqrt(max(1.e-20, PCAMatrix[0]));
    if (PCADominance < 0.55 || abs(PCAActivity) < 0.5)
    {
        return 0;
    }
    if (PCAActivity > 0.)
    {
        return 1;
    }
    return -1;
}

void PCATests()
{
    int K, Failures;
    Failures = 0;
    for (K = 0; K < 150; K++)
    {
        PCAClose[K] = 1.;
    }
    if (PCAEvaluate() != 0)
    {
        Failures++;
    }
    for (K = 0; K < 150; K++)
    {
        PCAClose[K] = exp(-0.001 * K);
    }
    if (PCAEvaluate() != 1)
    {
        Failures++;
    }
    for (K = 0; K < 150; K++)
    {
        PCAClose[K] = 1. / PCAClose[K];
    }
    if (PCAEvaluate() != -1)
    {
        Failures++;
    }
    PCAClose[0] = 0.;
    if (PCAEvaluate() != 0)
    {
        Failures++;
    }
    file_write("Log/TS01_CovariancePCA_test.txt", strf("4 checks; %d failures\n", Failures), 0);
}

var PCAResidualNorm()
{
    int A, B;
    var Lambda, Product, Residual;
    Lambda = 0.;
    Residual = 0.;
    for (A = 0; A < 5; A++)
    {
        for (B = 0; B < 5; B++)
        {
            Lambda += PCAVector[A] * PCAMatrix[A * 5 + B] * PCAVector[B];
        }
    }
    for (A = 0; A < 5; A++)
    {
        Product = 0.;
        for (B = 0; B < 5; B++)
        {
            Product += PCAMatrix[A * 5 + B] * PCAVector[B];
        }
        Product -= Lambda * PCAVector[A];
        Residual += Product * Product;
    }
    return sqrt(Residual);
}
var PCAEffectiveDimension()
{
    int A, B;
    var Trace, SquaredTrace;
    Trace = 0.;
    SquaredTrace = 0.;
    for (A = 0; A < 5; A++)
    {
        Trace += PCAMatrix[A * 5 + A];
        for (B = 0; B < 5; B++)
        {
            SquaredTrace += PCAMatrix[A * 5 + B] * PCAMatrix[A * 5 + B];
        }
    }
    if (SquaredTrace < 1.e-40)
    {
        return 0.;
    }
    return Trace * Trace / SquaredTrace;
}
var PCALoadingConcentration()
{
    int A;
    var FourthMoment, SecondMoment;
    FourthMoment = 0.;
    SecondMoment = 0.;
    for (A = 0; A < 5; A++)
    {
        SecondMoment += PCAVector[A] * PCAVector[A];
        FourthMoment += pow(PCAVector[A], 4.);
    }
    if (SecondMoment <= 0.)
    {
        return 0.;
    }
    return FourthMoment / (SecondMoment * SecondMoment);
}
void PCAResearchDiagnostics()
{
    printf("\nPCA effective dimension %.6g; loading concentration %.6g; residual %.6g",
           PCAEffectiveDimension(), PCALoadingConcentration(), PCAResidualNorm());
}

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

void PCACase_quiet_cycle()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 150; K++)
    {
        PCAClose[K] = 1.0 * exp(0.0005 * sin(0.17 * K));
    }
    Original = PCAEvaluate();
    PCAExpect(Original >= -1 && Original <= 1, "quiet_cycle: bounded direction");
    Again = PCAEvaluate();
    PCAExpect(Again == Original, "quiet_cycle: repeatable estimate");
    for (K = 0; K < 150; K++)
    {
        PCAClose[K] *= 7.;
    }
    Scaled = PCAEvaluate();
    PCAExpect(Scaled == Original, "quiet_cycle: price-unit invariance");
    for (K = 0; K < 150; K++)
    {
        PCAClose[K] = 1. / PCAClose[K];
    }
    Reflected = PCAEvaluate();
    PCAExpect(Reflected == -Original, "quiet_cycle: directional reflection");
    PCAClose[75] = 0.;
    PCAExpect(PCAEvaluate() == 0, "quiet_cycle: missing price rejected");
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

void PCAExtendedTests()
{
    PCAExtendedCount = 0;
    PCAExtendedFailures = 0;
    file_write("Log/TS01_CovariancePCA_extended.txt", "TS01_CovariancePCA: extended properties\n",
               0);
    PCACase_quiet_cycle();
    PCACase_mixed_cycles();
    PCACase_persistent_upward();
    PCACase_persistent_downward();
    PCACase_slow_curve();
    PCACase_rough_curve();
    PCACase_accelerating_path();
    PCACase_decelerating_path();
    PCACase_volatility_ramp();
    PCACase_volatility_decay();
    PCACase_cycle_with_drift();
    PCACase_near_zero_prices();
    PCACase_large_price_units();
    PCACase_high_frequency_chop();
    PCACase_long_wave_trend();
    PCACase_opposing_scales();
    PCACase_nonlinear_curve();
    PCACase_amplitude_modulation();
    PCACase_decaying_event();
    PCACase_time_varying_frequency();
    PCACase_slow_fast_cancellation();
    file_append("Log/TS01_CovariancePCA_extended.txt",
                strf("RESULT: %d checks; %d failures\n", PCAExtendedCount, PCAExtendedFailures));
}

function run()
{
#ifdef STX_SELFTEST
    if (is(INITRUN))
    {
        PCATests();
        PCAExtendedTests();
        quit("PCA tests complete");
    }
    return;
#endif
    int K, Side;
    var Budget, PerLot, Volume;
    BarPeriod = 60;
    LookBack = 151;
    StartDate = 20240101;
    EndDate = 20241231;
    Capital = 10000.;
    Hedge = 0;
    MaxLong = 1;
    MaxShort = 1;
    if (!asset(PCAAsset))
    {
        return;
    }
    algo("PCA01");
    if (is(EXITRUN))
    {
        PCAResearchDiagnostics();
        return;
    }
    if (is(LOOKBACK))
    {
        return;
    }
    for (K = 0; K < 150; K++)
    {
        PCAClose[K] = priceClose(K + 1);
    }
    Side = PCAEvaluate();
    // Exit when the dominant common factor loses concentration.
    if (PCADominance < 0.35)
    {
        exitLong();
        exitShort();
        return;
    }
    if (Side == 0)
    {
        return;
    }
    if (Side > 0)
    {
        exitShort();
    }
    else
    {
        exitLong();
    }
    if (NumOpenLong + NumOpenShort > 0)
    {
        return;
    }
    if (PIP <= 0. || PIPCost <= 0. || LotAmount <= 0. || MarginCost <= 0.)
    {
        return;
    }
    if (Balance <= 0. || Equity < Balance * 0.85)
    {
        return;
    }
    Stop = 40. * PIP;
    TakeProfit = 100. * PIP;
    LifeTime = 16;
    Budget = Balance * 0.005;
    PerLot = (Stop + Spread) / PIP * PIPCost + Commission * LotAmount / 10000.;
    if (PerLot <= 0.)
    {
        return;
    }
    Volume = min(Budget / PerLot, 2000. / LotAmount);
    Volume = min(Volume, max(0., Equity - MarginVal) * 0.8 / MarginCost);
    if (Volume < 1.)
    {
        return;
    }
    Lots = floor(Volume);
    Margin = 0.;
    Risk = 0.;
    if (Side > 0)
    {
        enterLong();
    }
    else
    {
        enterShort();
    }
}