Haar Energy — The Multiscale Microscope
Picture a microscope with several magnification settings. At the finest setting, the market appears full of tiny alternating movements. At broader settings, some of those movements cancel while larger directional structures become visible. This program uses a Haar wavelet transformation to separate those scales rather than fitting a covariance component, an equilibrium spread, or a latent state curve.

The input is a chronological block of completed price returns. The transformation repeatedly pairs neighboring observations. Each pair produces an average describing shared movement and a detail describing disagreement inside the pair. The averages are paired again at the next level, producing progressively broader views of the same original information.

The program records how much detail energy appears at each scale. A large share of fine scale energy suggests that local noise or rapid alternation dominates the picture. A smaller fine scale share suggests that broader structures deserve more attention. The broadest average is also included when evaluating total energy, preventing persistent drift from disappearing merely because adjacent observations look similar.

Direction comes from the signs of recent average components at several intermediate scales. The strategy looks for agreement among the views associated with progressively longer intervals. Positive agreement supports a long position, while negative agreement supports a short position. The program does not infer direction from energy alone, because energy measures strength without distinguishing upward from downward movement.

Trades are considered only when the finest details are sufficiently subdued and the broader directional component is meaningful relative to total activity. When fine scale energy becomes dominant, existing positions can be closed. This exit reflects the idea that the clean broad structure has deteriorated into a noisier environment, even if the latest price has not yet crossed a conventional moving average.

The diagnostic layer checks energy preservation between the original returns and the transformed representation. It also calculates an entropy measure across detail scales and counts agreement between neighboring phases. These checks help identify whether the transformation is behaving numerically and whether movement is concentrated or dispersed across scales.

The microscope reveals structure; it does not prove that the structure will persist. A nonoverlapping Haar transformation is sensitive to where the observation window begins and ends. A trend can also reverse immediately after appearing clean across several scales. Protective stops, constrained sizing, profit targets, and a holding limit remain necessary because visual coherence and predictive reliability are different properties.

Code
// Independent model 04: discrete Haar multiresolution energy and phase alignment.
#include <default.c>

var HaarClose[66];
var HaarWork[64];
var HaarApprox[64];
var HaarEnergy[6];
var HaarPhase[6];
var HaarRatio = 0.;
var HaarDirection = 0.;

int HaarTransformSignal()
{
    int I, Level, Size;
    var Detail, Fine, Coarse, Total;
    HaarRatio = 0.;
    HaarDirection = 0.;
    for (I = 0; I < 66; I++)
    {
        if (!(HaarClose[I] > 0.))
        {
            return 0;
        }
    }
    // DWT input is chronological. Boundary phase always ends at latest closed bar.
    for (I = 0; I < 64; I++)
    {
        HaarWork[I] = log(HaarClose[63 - I] / HaarClose[64 - I]);
    }
    Size = 64;
    for (Level = 0; Level < 6; Level++)
    {
        HaarEnergy[Level] = 0.;
        for (I = 0; I < Size / 2; I++)
        {
            HaarApprox[I] = (HaarWork[2 * I] + HaarWork[2 * I + 1]) / sqrt(2.);
            Detail = (HaarWork[2 * I] - HaarWork[2 * I + 1]) / sqrt(2.);
            HaarEnergy[Level] += Detail * Detail;
        }
        HaarPhase[Level] = HaarApprox[Size / 2 - 1];
        Size /= 2;
        for (I = 0; I < Size; I++)
        {
            HaarWork[I] = HaarApprox[I];
        }
    }
    Fine = HaarEnergy[0] + HaarEnergy[1];
    Coarse = HaarEnergy[2] + HaarEnergy[3] + HaarEnergy[4] + HaarEnergy[5];
    Total = Fine + Coarse + HaarWork[0] * HaarWork[0];
    if (Total < 1.e-20)
    {
        return 0;
    }
    HaarRatio = Fine / Total;
    HaarDirection = HaarPhase[3] / sqrt(Total);
    // Low fine-scale energy with consistent 4-, 8-, and 16-bar phases.
    if (HaarRatio > 0.45 || abs(HaarDirection) < 0.15)
    {
        return 0;
    }
    if (HaarPhase[1] > 0. && HaarPhase[2] > 0. && HaarPhase[3] > 0.)
    {
        return 1;
    }
    if (HaarPhase[1] < 0. && HaarPhase[2] < 0. && HaarPhase[3] < 0.)
    {
        return -1;
    }
    return 0;
}

void HaarSelfCheck()
{
    int I, Broken;
    Broken = 0;
    for (I = 0; I < 66; I++)
    {
        HaarClose[I] = 1.;
    }
    if (HaarTransformSignal() != 0)
    {
        Broken++;
    }
    for (I = 0; I < 66; I++)
    {
        HaarClose[I] = exp(-0.001 * I);
    }
    if (HaarTransformSignal() != 1)
    {
        Broken++;
    }
    for (I = 0; I < 66; I++)
    {
        HaarClose[I] = exp(0.001 * I);
    }
    if (HaarTransformSignal() != -1)
    {
        Broken++;
    }
    HaarClose[8] = -1.;
    if (HaarTransformSignal() != 0)
    {
        Broken++;
    }
    file_write("Log/TS04_HaarEnergy_test.txt", strf("4 checks; %d failures\n", Broken), 0);
}

var HaarSpectralEntropy()
{
    int L;
    var Total, Probability, Entropy;
    Total = 0.;
    Entropy = 0.;
    for (L = 0; L < 6; L++)
    {
        Total += HaarEnergy[L];
    }
    if (Total < 1.e-24)
    {
        return 0.;
    }
    for (L = 0; L < 6; L++)
    {
        Probability = HaarEnergy[L] / Total;
        if (Probability > 1.e-15)
        {
            Entropy -= Probability * log(Probability) / log(6.);
        }
    }
    return Entropy;
}
var HaarParsevalError()
{
    int L;
    var TimeEnergy, WaveEnergy, R;
    TimeEnergy = 0.;
    WaveEnergy = HaarWork[0] * HaarWork[0];
    for (L = 0; L < 64; L++)
    {
        R = log(HaarClose[L] / HaarClose[L + 1]);
        TimeEnergy += R * R;
    }
    for (L = 0; L < 6; L++)
    {
        WaveEnergy += HaarEnergy[L];
    }
    if (TimeEnergy < 1.e-24)
    {
        return 0.;
    }
    return abs(TimeEnergy - WaveEnergy) / TimeEnergy;
}
int HaarPhaseAgreements()
{
    int L, Count;
    Count = 0;
    for (L = 0; L < 5; L++)
    {
        if (HaarPhase[L] * HaarPhase[L + 1] > 0.)
        {
            Count++;
        }
    }
    return Count;
}
void HaarResearchDiagnostics()
{
    printf("\nHaar entropy %.6g; Parseval relative error %.6g; phase agreements %d",
           HaarSpectralEntropy(), HaarParsevalError(), HaarPhaseAgreements());
}

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

void HaarCase_quiet_cycle()
{
    int K, Original, Again, Scaled, Reflected;
    for (K = 0; K < 66; K++)
    {
        HaarClose[K] = 1.0 * exp(0.0005 * sin(0.17 * K));
    }
    Original = HaarTransformSignal();
    HaarExpect(Original >= -1 && Original <= 1, "quiet_cycle: bounded direction");
    Again = HaarTransformSignal();
    HaarExpect(Again == Original, "quiet_cycle: repeatable estimate");
    for (K = 0; K < 66; K++)
    {
        HaarClose[K] *= 7.;
    }
    Scaled = HaarTransformSignal();
    HaarExpect(Scaled == Original, "quiet_cycle: price-unit invariance");
    for (K = 0; K < 66; K++)
    {
        HaarClose[K] = 1. / HaarClose[K];
    }
    Reflected = HaarTransformSignal();
    HaarExpect(Reflected == -Original, "quiet_cycle: directional reflection");
    HaarClose[33] = 0.;
    HaarExpect(HaarTransformSignal() == 0, "quiet_cycle: missing price rejected");
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

void HaarExtendedTests()
{
    HaarExtendedCount = 0;
    HaarExtendedFailures = 0;
    file_write("Log/TS04_HaarEnergy_extended.txt", "TS04_HaarEnergy: extended properties\n", 0);
    HaarCase_quiet_cycle();
    HaarCase_mixed_cycles();
    HaarCase_persistent_upward();
    HaarCase_persistent_downward();
    HaarCase_slow_curve();
    HaarCase_rough_curve();
    HaarCase_accelerating_path();
    HaarCase_decelerating_path();
    HaarCase_volatility_ramp();
    HaarCase_volatility_decay();
    HaarCase_cycle_with_drift();
    HaarCase_near_zero_prices();
    HaarCase_large_price_units();
    HaarCase_high_frequency_chop();
    HaarCase_long_wave_trend();
    HaarCase_opposing_scales();
    HaarCase_nonlinear_curve();
    HaarCase_amplitude_modulation();
    HaarCase_decaying_event();
    HaarCase_time_varying_frequency();
    HaarCase_slow_fast_cancellation();
    file_append("Log/TS04_HaarEnergy_extended.txt",
                strf("RESULT: %d checks; %d failures\n", HaarExtendedCount, HaarExtendedFailures));
}

function run()
{
#ifdef STX_SELFTEST
    if (is(INITRUN))
    {
        HaarSelfCheck();
        HaarExtendedTests();
        quit("Haar tests complete");
    }
    return;
#endif
    int I, WaveSide;
    var AllowedLots, Cost;
    BarPeriod = 60;
    LookBack = 67;
    StartDate = 20240101;
    EndDate = 20241231;
    Capital = 10000.;
    MaxLong = 1;
    MaxShort = 1;
    Hedge = 0;
    if (!asset("EUR/USD"))
    {
        return;
    }
    algo("HAAR04");
    if (is(EXITRUN))
    {
        HaarResearchDiagnostics();
        return;
    }
    if (is(LOOKBACK))
    {
        return;
    }
    for (I = 0; I < 66; I++)
    {
        HaarClose[I] = priceClose(I + 1);
    }
    WaveSide = HaarTransformSignal();
    if (HaarRatio > 0.65)
    {
        exitLong();
        exitShort();
        return;
    }
    if (WaveSide > 0)
    {
        exitShort();
    }
    if (WaveSide < 0)
    {
        exitLong();
    }
    if (WaveSide == 0 || NumOpenLong + NumOpenShort > 0)
    {
        return;
    }
    if (PIP <= 0. || PIPCost <= 0. || LotAmount <= 0. || MarginCost <= 0.)
    {
        return;
    }
    if (Balance <= 0. || Equity < Balance * 0.85)
    {
        return;
    }
    Stop = 45. * PIP;
    TakeProfit = 135. * PIP;
    LifeTime = 32;
    Cost = PIPCost * (Stop + Spread) / PIP + Commission * LotAmount / 10000.;
    if (Cost <= 0.)
    {
        return;
    }
    AllowedLots = min(2000. / LotAmount, Balance * 0.005 / Cost);
    AllowedLots = min(AllowedLots, max(0., Equity - MarginVal) * 0.8 / MarginCost);
    if (AllowedLots < 1.)
    {
        return;
    }
    Lots = floor(AllowedLots);
    Margin = 0.;
    Risk = 0.;
    if (WaveSide > 0)
    {
        enterLong();
    }
    else
    {
        enterShort();
    }
}