// Independent model 09: ordinal entropy, return-curve recurrence and analogues.
#include <default.c>
var NNPrices[180];
var NNForecast = 0.;
var NNEntropy = 1.;
int NNUsed = 0;
int NNHorizons[3] = {1, 4, 16};
int NNOrdinal(var A, var B, var C)
{
if (A <= B && B <= C)
{
return 0;
}
if (A <= C && C < B)
{
return 1;
}
if (B < A && A <= C)
{
return 2;
}
if (B <= C && C < A)
{
return 3;
}
if (C < A && A <= B)
{
return 4;
}
return 5;
}
int NNFindRecurrences()
{
int T, J, Rank, Slot, Pattern;
int Frequency[6];
var CurrentCurve[3];
var Scale[3];
var Mean[3];
var Nearest[8];
var Outcomes[8];
var A, B, C, Feature, Difference, Distance, Target, Probability, Weight, SumWeight, Variance;
NNForecast = 0.;
NNUsed = 0.;
NNEntropy = 0.;
for (T = 0; T < 180; T++)
{
if (!(NNPrices[T] > 0.))
{
return 0;
}
}
for (Pattern = 0; Pattern < 6; Pattern++)
{
Frequency[Pattern] = 0;
}
for (T = 1; T <= 48; T++)
{
A = log(NNPrices[T] / NNPrices[T + 1]);
B = log(NNPrices[T + 1] / NNPrices[T + 2]);
C = log(NNPrices[T + 2] / NNPrices[T + 3]);
Frequency[NNOrdinal(A, B, C)]++;
}
for (Pattern = 0; Pattern < 6; Pattern++)
{
Probability = Frequency[Pattern] / 48.;
if (Probability > 0.)
{
NNEntropy -= Probability * log(Probability) / log(6.);
}
}
for (J = 0; J < 3; J++)
{
Mean[J] = 0.;
Scale[J] = 0.;
for (T = 12; T <= 140; T++)
{
Mean[J] += log(NNPrices[T] / NNPrices[T + NNHorizons[J]]) / NNHorizons[J] / 129.;
}
for (T = 12; T <= 140; T++)
{
Feature = log(NNPrices[T] / NNPrices[T + NNHorizons[J]]) / NNHorizons[J];
Scale[J] += (Feature - Mean[J]) * (Feature - Mean[J]) / 129.;
}
if (Scale[J] < 1.e-22)
{
return 0;
}
CurrentCurve[J] = log(NNPrices[0] / NNPrices[NNHorizons[J]]) / NNHorizons[J];
}
for (Rank = 0; Rank < 8; Rank++)
{
Nearest[Rank] = 1.e100;
Outcomes[Rank] = 0.;
}
for (T = 12; T <= 140; T++)
{
Distance = 0.;
for (J = 0; J < 3; J++)
{
Feature = log(NNPrices[T] / NNPrices[T + NNHorizons[J]]) / NNHorizons[J];
Difference = CurrentCurve[J] - Feature;
Distance += Difference * Difference / Scale[J];
}
// The forward target of every historical analogue is already observable.
Target = log(NNPrices[T - 4] / NNPrices[T]);
for (Rank = 0; Rank < 8; Rank++)
{
if (Distance < Nearest[Rank])
{
for (Slot = 7; Slot > Rank; Slot--)
{
Nearest[Slot] = Nearest[Slot - 1];
Outcomes[Slot] = Outcomes[Slot - 1];
}
Nearest[Rank] = Distance;
Outcomes[Rank] = Target;
break;
}
}
}
SumWeight = 0.;
Variance = 0.;
for (Rank = 0; Rank < 8; Rank++)
{
Weight = 1. / (0.1 + Nearest[Rank]);
NNForecast += Weight * Outcomes[Rank];
SumWeight += Weight;
NNUsed++;
}
if (SumWeight <= 0.)
{
return 0;
}
NNForecast /= SumWeight;
for (Rank = 0; Rank < 8; Rank++)
{
Difference = Outcomes[Rank] - NNForecast;
Variance += Difference * Difference / 8.;
}
if (NNEntropy > 0.97 || Nearest[7] > 4.)
{
return 0;
}
if (abs(NNForecast) < sqrt(max(1.e-22, Variance)) * 0.5)
{
return 0;
}
if (NNForecast > 0.)
{
return 1;
}
if (NNForecast < 0.)
{
return -1;
}
return 0;
}
void NNTestHistory()
{
int T, One, Mirror, Mistakes;
Mistakes = 0;
for (T = 0; T < 180; T++)
{
NNPrices[T] = 1.;
}
if (NNFindRecurrences() != 0)
{
Mistakes++;
}
for (T = 0; T < 180; T++)
{
NNPrices[T] = exp(0.003 * sin(0.17 * T) + 0.001 * cos(0.41 * T));
}
One = NNFindRecurrences();
if (NNUsed != 8 || One < -1 || One > 1)
{
Mistakes++;
}
for (T = 0; T < 180; T++)
{
NNPrices[T] = 1. / NNPrices[T];
}
Mirror = NNFindRecurrences();
if (Mirror != -One)
{
Mistakes++;
}
NNPrices[0] = -1.;
if (NNFindRecurrences() != 0)
{
Mistakes++;
}
file_write("Log/TS09_EntropyAnalogues_test.txt", strf("4 checks; %d failures\n", Mistakes), 0);
}
var NNRecurrenceRate(var MaximumDistance)
{
int T, J, Hits;
var Distance, Difference, Current, Historic;
if (MaximumDistance <= 0.)
{
return 0.;
}
Hits = 0;
for (T = 16; T <= 140; T++)
{
Distance = 0.;
for (J = 0; J < 3; J++)
{
Current = log(NNPrices[0] / NNPrices[NNHorizons[J]]) / NNHorizons[J];
Historic = log(NNPrices[T] / NNPrices[T + NNHorizons[J]]) / NNHorizons[J];
Difference = Current - Historic;
Distance += Difference * Difference;
}
if (sqrt(Distance) < MaximumDistance)
{
Hits++;
}
}
return Hits / 125.;
}
var NNForwardTargetDispersion()
{
int T;
var Y, MeanTarget, VarTarget;
MeanTarget = 0.;
VarTarget = 0.;
for (T = 12; T <= 140; T++)
{
MeanTarget += log(NNPrices[T - 4] / NNPrices[T]) / 129.;
}
for (T = 12; T <= 140; T++)
{
Y = log(NNPrices[T - 4] / NNPrices[T]) - MeanTarget;
VarTarget += Y * Y / 129.;
}
return sqrt(VarTarget);
}
var NNInformationComplement()
{
return max(0., 1. - NNEntropy);
}
void NNResearchDiagnostics()
{
printf(
"\nAnalogues %d; recurrence rate %.6g; target dispersion %.6g; information complement %.6g",
NNUsed, NNRecurrenceRate(0.001), NNForwardTargetDispersion(), NNInformationComplement());
}
// ============================================================================
// EXTENDED REGRESSION SUITE: deterministic properties over market regimes
// These functions run ONLY under STX_SELFTEST; they never place orders.
// ============================================================================
int NNExtendedCount = 0;
int NNExtendedFailures = 0;
void NNExpect(int Passed, string Description)
{
NNExtendedCount++;
if (!Passed)
{
NNExtendedFailures++;
file_append("Log/TS09_EntropyAnalogues_extended.txt", strf("FAIL: %s\n", Description));
}
}
void NNCase_quiet_cycle()
{
int K, Original, Again, Scaled, Reflected;
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1.0 * exp(0.0005 * sin(0.17 * K));
}
Original = NNFindRecurrences();
NNExpect(Original >= -1 && Original <= 1, "quiet_cycle: bounded direction");
Again = NNFindRecurrences();
NNExpect(Again == Original, "quiet_cycle: repeatable estimate");
for (K = 0; K < 180; K++)
{
NNPrices[K] *= 7.;
}
Scaled = NNFindRecurrences();
NNExpect(Scaled == Original, "quiet_cycle: price-unit invariance");
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1. / NNPrices[K];
}
Reflected = NNFindRecurrences();
NNExpect(Reflected == -Original, "quiet_cycle: directional reflection");
NNPrices[90] = 0.;
NNExpect(NNFindRecurrences() == 0, "quiet_cycle: missing price rejected");
}
void NNCase_mixed_cycles()
{
int K, Original, Again, Scaled, Reflected;
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1.0 * exp(0.003 * sin(0.23 * K) + 0.0007 * cos(0.81 * K));
}
Original = NNFindRecurrences();
NNExpect(Original >= -1 && Original <= 1, "mixed_cycles: bounded direction");
Again = NNFindRecurrences();
NNExpect(Again == Original, "mixed_cycles: repeatable estimate");
for (K = 0; K < 180; K++)
{
NNPrices[K] *= 7.;
}
Scaled = NNFindRecurrences();
NNExpect(Scaled == Original, "mixed_cycles: price-unit invariance");
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1. / NNPrices[K];
}
Reflected = NNFindRecurrences();
NNExpect(Reflected == -Original, "mixed_cycles: directional reflection");
NNPrices[90] = 0.;
NNExpect(NNFindRecurrences() == 0, "mixed_cycles: missing price rejected");
}
void NNCase_persistent_upward()
{
int K, Original, Again, Scaled, Reflected;
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1.0 * exp(-0.001 * K + 0.0001 * sin(0.53 * K));
}
Original = NNFindRecurrences();
NNExpect(Original >= -1 && Original <= 1, "persistent_upward: bounded direction");
Again = NNFindRecurrences();
NNExpect(Again == Original, "persistent_upward: repeatable estimate");
for (K = 0; K < 180; K++)
{
NNPrices[K] *= 7.;
}
Scaled = NNFindRecurrences();
NNExpect(Scaled == Original, "persistent_upward: price-unit invariance");
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1. / NNPrices[K];
}
Reflected = NNFindRecurrences();
NNExpect(Reflected == -Original, "persistent_upward: directional reflection");
NNPrices[90] = 0.;
NNExpect(NNFindRecurrences() == 0, "persistent_upward: missing price rejected");
}
void NNCase_persistent_downward()
{
int K, Original, Again, Scaled, Reflected;
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1.0 * exp(0.001 * K + 0.0001 * cos(0.47 * K));
}
Original = NNFindRecurrences();
NNExpect(Original >= -1 && Original <= 1, "persistent_downward: bounded direction");
Again = NNFindRecurrences();
NNExpect(Again == Original, "persistent_downward: repeatable estimate");
for (K = 0; K < 180; K++)
{
NNPrices[K] *= 7.;
}
Scaled = NNFindRecurrences();
NNExpect(Scaled == Original, "persistent_downward: price-unit invariance");
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1. / NNPrices[K];
}
Reflected = NNFindRecurrences();
NNExpect(Reflected == -Original, "persistent_downward: directional reflection");
NNPrices[90] = 0.;
NNExpect(NNFindRecurrences() == 0, "persistent_downward: missing price rejected");
}
void NNCase_slow_curve()
{
int K, Original, Again, Scaled, Reflected;
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1.0 * exp(0.004 * cos(0.08 * K) + 0.0002 * sin(0.7 * K));
}
Original = NNFindRecurrences();
NNExpect(Original >= -1 && Original <= 1, "slow_curve: bounded direction");
Again = NNFindRecurrences();
NNExpect(Again == Original, "slow_curve: repeatable estimate");
for (K = 0; K < 180; K++)
{
NNPrices[K] *= 7.;
}
Scaled = NNFindRecurrences();
NNExpect(Scaled == Original, "slow_curve: price-unit invariance");
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1. / NNPrices[K];
}
Reflected = NNFindRecurrences();
NNExpect(Reflected == -Original, "slow_curve: directional reflection");
NNPrices[90] = 0.;
NNExpect(NNFindRecurrences() == 0, "slow_curve: missing price rejected");
}
void NNCase_rough_curve()
{
int K, Original, Again, Scaled, Reflected;
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1.0 * exp(0.001 * sin(1.7 * K) + 0.0005 * cos(2.3 * K));
}
Original = NNFindRecurrences();
NNExpect(Original >= -1 && Original <= 1, "rough_curve: bounded direction");
Again = NNFindRecurrences();
NNExpect(Again == Original, "rough_curve: repeatable estimate");
for (K = 0; K < 180; K++)
{
NNPrices[K] *= 7.;
}
Scaled = NNFindRecurrences();
NNExpect(Scaled == Original, "rough_curve: price-unit invariance");
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1. / NNPrices[K];
}
Reflected = NNFindRecurrences();
NNExpect(Reflected == -Original, "rough_curve: directional reflection");
NNPrices[90] = 0.;
NNExpect(NNFindRecurrences() == 0, "rough_curve: missing price rejected");
}
void NNCase_accelerating_path()
{
int K, Original, Again, Scaled, Reflected;
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1.0 * exp(-0.0001 * K - 0.000002 * K * K + 0.0002 * sin(0.41 * K));
}
Original = NNFindRecurrences();
NNExpect(Original >= -1 && Original <= 1, "accelerating_path: bounded direction");
Again = NNFindRecurrences();
NNExpect(Again == Original, "accelerating_path: repeatable estimate");
for (K = 0; K < 180; K++)
{
NNPrices[K] *= 7.;
}
Scaled = NNFindRecurrences();
NNExpect(Scaled == Original, "accelerating_path: price-unit invariance");
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1. / NNPrices[K];
}
Reflected = NNFindRecurrences();
NNExpect(Reflected == -Original, "accelerating_path: directional reflection");
NNPrices[90] = 0.;
NNExpect(NNFindRecurrences() == 0, "accelerating_path: missing price rejected");
}
void NNCase_decelerating_path()
{
int K, Original, Again, Scaled, Reflected;
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1.0 * exp(-0.0008 * K + 0.000002 * K * K + 0.0002 * cos(0.31 * K));
}
Original = NNFindRecurrences();
NNExpect(Original >= -1 && Original <= 1, "decelerating_path: bounded direction");
Again = NNFindRecurrences();
NNExpect(Again == Original, "decelerating_path: repeatable estimate");
for (K = 0; K < 180; K++)
{
NNPrices[K] *= 7.;
}
Scaled = NNFindRecurrences();
NNExpect(Scaled == Original, "decelerating_path: price-unit invariance");
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1. / NNPrices[K];
}
Reflected = NNFindRecurrences();
NNExpect(Reflected == -Original, "decelerating_path: directional reflection");
NNPrices[90] = 0.;
NNExpect(NNFindRecurrences() == 0, "decelerating_path: missing price rejected");
}
void NNCase_volatility_ramp()
{
int K, Original, Again, Scaled, Reflected;
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1.0 * exp((0.0001 + K * 0.00001) * sin(0.37 * K));
}
Original = NNFindRecurrences();
NNExpect(Original >= -1 && Original <= 1, "volatility_ramp: bounded direction");
Again = NNFindRecurrences();
NNExpect(Again == Original, "volatility_ramp: repeatable estimate");
for (K = 0; K < 180; K++)
{
NNPrices[K] *= 7.;
}
Scaled = NNFindRecurrences();
NNExpect(Scaled == Original, "volatility_ramp: price-unit invariance");
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1. / NNPrices[K];
}
Reflected = NNFindRecurrences();
NNExpect(Reflected == -Original, "volatility_ramp: directional reflection");
NNPrices[90] = 0.;
NNExpect(NNFindRecurrences() == 0, "volatility_ramp: missing price rejected");
}
void NNCase_volatility_decay()
{
int K, Original, Again, Scaled, Reflected;
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1.0 * exp(0.006 * exp(-0.02 * K) * cos(0.7 * K));
}
Original = NNFindRecurrences();
NNExpect(Original >= -1 && Original <= 1, "volatility_decay: bounded direction");
Again = NNFindRecurrences();
NNExpect(Again == Original, "volatility_decay: repeatable estimate");
for (K = 0; K < 180; K++)
{
NNPrices[K] *= 7.;
}
Scaled = NNFindRecurrences();
NNExpect(Scaled == Original, "volatility_decay: price-unit invariance");
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1. / NNPrices[K];
}
Reflected = NNFindRecurrences();
NNExpect(Reflected == -Original, "volatility_decay: directional reflection");
NNPrices[90] = 0.;
NNExpect(NNFindRecurrences() == 0, "volatility_decay: missing price rejected");
}
void NNCase_cycle_with_drift()
{
int K, Original, Again, Scaled, Reflected;
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1.0 * exp(-0.0002 * K + 0.003 * sin(0.19 * K) + 0.0005 * cos(0.61 * K));
}
Original = NNFindRecurrences();
NNExpect(Original >= -1 && Original <= 1, "cycle_with_drift: bounded direction");
Again = NNFindRecurrences();
NNExpect(Again == Original, "cycle_with_drift: repeatable estimate");
for (K = 0; K < 180; K++)
{
NNPrices[K] *= 7.;
}
Scaled = NNFindRecurrences();
NNExpect(Scaled == Original, "cycle_with_drift: price-unit invariance");
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1. / NNPrices[K];
}
Reflected = NNFindRecurrences();
NNExpect(Reflected == -Original, "cycle_with_drift: directional reflection");
NNPrices[90] = 0.;
NNExpect(NNFindRecurrences() == 0, "cycle_with_drift: missing price rejected");
}
void NNCase_near_zero_prices()
{
int K, Original, Again, Scaled, Reflected;
for (K = 0; K < 180; K++)
{
NNPrices[K] = 0.0001 * exp(0.002 * sin(0.29 * K) + 0.001 * cos(0.13 * K));
}
Original = NNFindRecurrences();
NNExpect(Original >= -1 && Original <= 1, "near_zero_prices: bounded direction");
Again = NNFindRecurrences();
NNExpect(Again == Original, "near_zero_prices: repeatable estimate");
for (K = 0; K < 180; K++)
{
NNPrices[K] *= 7.;
}
Scaled = NNFindRecurrences();
NNExpect(Scaled == Original, "near_zero_prices: price-unit invariance");
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1. / NNPrices[K];
}
Reflected = NNFindRecurrences();
NNExpect(Reflected == -Original, "near_zero_prices: directional reflection");
NNPrices[90] = 0.;
NNExpect(NNFindRecurrences() == 0, "near_zero_prices: missing price rejected");
}
void NNCase_large_price_units()
{
int K, Original, Again, Scaled, Reflected;
for (K = 0; K < 180; K++)
{
NNPrices[K] = 10000.0 * exp(0.003 * sin(0.11 * K) + 0.0008 * cos(0.43 * K));
}
Original = NNFindRecurrences();
NNExpect(Original >= -1 && Original <= 1, "large_price_units: bounded direction");
Again = NNFindRecurrences();
NNExpect(Again == Original, "large_price_units: repeatable estimate");
for (K = 0; K < 180; K++)
{
NNPrices[K] *= 7.;
}
Scaled = NNFindRecurrences();
NNExpect(Scaled == Original, "large_price_units: price-unit invariance");
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1. / NNPrices[K];
}
Reflected = NNFindRecurrences();
NNExpect(Reflected == -Original, "large_price_units: directional reflection");
NNPrices[90] = 0.;
NNExpect(NNFindRecurrences() == 0, "large_price_units: missing price rejected");
}
void NNCase_high_frequency_chop()
{
int K, Original, Again, Scaled, Reflected;
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1.0 * exp(0.0008 * cos(2.8 * K) + 0.001 * sin(0.23 * K));
}
Original = NNFindRecurrences();
NNExpect(Original >= -1 && Original <= 1, "high_frequency_chop: bounded direction");
Again = NNFindRecurrences();
NNExpect(Again == Original, "high_frequency_chop: repeatable estimate");
for (K = 0; K < 180; K++)
{
NNPrices[K] *= 7.;
}
Scaled = NNFindRecurrences();
NNExpect(Scaled == Original, "high_frequency_chop: price-unit invariance");
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1. / NNPrices[K];
}
Reflected = NNFindRecurrences();
NNExpect(Reflected == -Original, "high_frequency_chop: directional reflection");
NNPrices[90] = 0.;
NNExpect(NNFindRecurrences() == 0, "high_frequency_chop: missing price rejected");
}
void NNCase_long_wave_trend()
{
int K, Original, Again, Scaled, Reflected;
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1.0 * exp(-0.0005 * K + 0.002 * cos(0.07 * K));
}
Original = NNFindRecurrences();
NNExpect(Original >= -1 && Original <= 1, "long_wave_trend: bounded direction");
Again = NNFindRecurrences();
NNExpect(Again == Original, "long_wave_trend: repeatable estimate");
for (K = 0; K < 180; K++)
{
NNPrices[K] *= 7.;
}
Scaled = NNFindRecurrences();
NNExpect(Scaled == Original, "long_wave_trend: price-unit invariance");
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1. / NNPrices[K];
}
Reflected = NNFindRecurrences();
NNExpect(Reflected == -Original, "long_wave_trend: directional reflection");
NNPrices[90] = 0.;
NNExpect(NNFindRecurrences() == 0, "long_wave_trend: missing price rejected");
}
void NNCase_opposing_scales()
{
int K, Original, Again, Scaled, Reflected;
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1.0 * exp(0.005 * sin(0.09 * K) - 0.002 * sin(0.59 * K));
}
Original = NNFindRecurrences();
NNExpect(Original >= -1 && Original <= 1, "opposing_scales: bounded direction");
Again = NNFindRecurrences();
NNExpect(Again == Original, "opposing_scales: repeatable estimate");
for (K = 0; K < 180; K++)
{
NNPrices[K] *= 7.;
}
Scaled = NNFindRecurrences();
NNExpect(Scaled == Original, "opposing_scales: price-unit invariance");
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1. / NNPrices[K];
}
Reflected = NNFindRecurrences();
NNExpect(Reflected == -Original, "opposing_scales: directional reflection");
NNPrices[90] = 0.;
NNExpect(NNFindRecurrences() == 0, "opposing_scales: missing price rejected");
}
void NNCase_nonlinear_curve()
{
int K, Original, Again, Scaled, Reflected;
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1.0 * exp(0.002 * sin(0.021 * K * K) + 0.001 * cos(0.33 * K));
}
Original = NNFindRecurrences();
NNExpect(Original >= -1 && Original <= 1, "nonlinear_curve: bounded direction");
Again = NNFindRecurrences();
NNExpect(Again == Original, "nonlinear_curve: repeatable estimate");
for (K = 0; K < 180; K++)
{
NNPrices[K] *= 7.;
}
Scaled = NNFindRecurrences();
NNExpect(Scaled == Original, "nonlinear_curve: price-unit invariance");
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1. / NNPrices[K];
}
Reflected = NNFindRecurrences();
NNExpect(Reflected == -Original, "nonlinear_curve: directional reflection");
NNPrices[90] = 0.;
NNExpect(NNFindRecurrences() == 0, "nonlinear_curve: missing price rejected");
}
void NNCase_amplitude_modulation()
{
int K, Original, Again, Scaled, Reflected;
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1.0 * exp(0.002 * sin(0.3 * K) * cos(0.04 * K));
}
Original = NNFindRecurrences();
NNExpect(Original >= -1 && Original <= 1, "amplitude_modulation: bounded direction");
Again = NNFindRecurrences();
NNExpect(Again == Original, "amplitude_modulation: repeatable estimate");
for (K = 0; K < 180; K++)
{
NNPrices[K] *= 7.;
}
Scaled = NNFindRecurrences();
NNExpect(Scaled == Original, "amplitude_modulation: price-unit invariance");
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1. / NNPrices[K];
}
Reflected = NNFindRecurrences();
NNExpect(Reflected == -Original, "amplitude_modulation: directional reflection");
NNPrices[90] = 0.;
NNExpect(NNFindRecurrences() == 0, "amplitude_modulation: missing price rejected");
}
void NNCase_decaying_event()
{
int K, Original, Again, Scaled, Reflected;
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1.0 * exp(0.01 * exp(-0.2 * K) + 0.0003 * sin(0.71 * K));
}
Original = NNFindRecurrences();
NNExpect(Original >= -1 && Original <= 1, "decaying_event: bounded direction");
Again = NNFindRecurrences();
NNExpect(Again == Original, "decaying_event: repeatable estimate");
for (K = 0; K < 180; K++)
{
NNPrices[K] *= 7.;
}
Scaled = NNFindRecurrences();
NNExpect(Scaled == Original, "decaying_event: price-unit invariance");
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1. / NNPrices[K];
}
Reflected = NNFindRecurrences();
NNExpect(Reflected == -Original, "decaying_event: directional reflection");
NNPrices[90] = 0.;
NNExpect(NNFindRecurrences() == 0, "decaying_event: missing price rejected");
}
void NNCase_time_varying_frequency()
{
int K, Original, Again, Scaled, Reflected;
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1.0 * exp(0.002 * cos(0.004 * K * K + 0.11 * K));
}
Original = NNFindRecurrences();
NNExpect(Original >= -1 && Original <= 1, "time_varying_frequency: bounded direction");
Again = NNFindRecurrences();
NNExpect(Again == Original, "time_varying_frequency: repeatable estimate");
for (K = 0; K < 180; K++)
{
NNPrices[K] *= 7.;
}
Scaled = NNFindRecurrences();
NNExpect(Scaled == Original, "time_varying_frequency: price-unit invariance");
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1. / NNPrices[K];
}
Reflected = NNFindRecurrences();
NNExpect(Reflected == -Original, "time_varying_frequency: directional reflection");
NNPrices[90] = 0.;
NNExpect(NNFindRecurrences() == 0, "time_varying_frequency: missing price rejected");
}
void NNCase_slow_fast_cancellation()
{
int K, Original, Again, Scaled, Reflected;
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1.0 * exp(0.004 * sin(0.07 * K) + 0.0013 * cos(0.97 * K));
}
Original = NNFindRecurrences();
NNExpect(Original >= -1 && Original <= 1, "slow_fast_cancellation: bounded direction");
Again = NNFindRecurrences();
NNExpect(Again == Original, "slow_fast_cancellation: repeatable estimate");
for (K = 0; K < 180; K++)
{
NNPrices[K] *= 7.;
}
Scaled = NNFindRecurrences();
NNExpect(Scaled == Original, "slow_fast_cancellation: price-unit invariance");
for (K = 0; K < 180; K++)
{
NNPrices[K] = 1. / NNPrices[K];
}
Reflected = NNFindRecurrences();
NNExpect(Reflected == -Original, "slow_fast_cancellation: directional reflection");
NNPrices[90] = 0.;
NNExpect(NNFindRecurrences() == 0, "slow_fast_cancellation: missing price rejected");
}
void NNExtendedTests()
{
NNExtendedCount = 0;
NNExtendedFailures = 0;
file_write("Log/TS09_EntropyAnalogues_extended.txt",
"TS09_EntropyAnalogues: extended properties\n", 0);
NNCase_quiet_cycle();
NNCase_mixed_cycles();
NNCase_persistent_upward();
NNCase_persistent_downward();
NNCase_slow_curve();
NNCase_rough_curve();
NNCase_accelerating_path();
NNCase_decelerating_path();
NNCase_volatility_ramp();
NNCase_volatility_decay();
NNCase_cycle_with_drift();
NNCase_near_zero_prices();
NNCase_large_price_units();
NNCase_high_frequency_chop();
NNCase_long_wave_trend();
NNCase_opposing_scales();
NNCase_nonlinear_curve();
NNCase_amplitude_modulation();
NNCase_decaying_event();
NNCase_time_varying_frequency();
NNCase_slow_fast_cancellation();
file_append("Log/TS09_EntropyAnalogues_extended.txt",
strf("RESULT: %d checks; %d failures\n", NNExtendedCount, NNExtendedFailures));
}
function run()
{
#ifdef STX_SELFTEST
if (is(INITRUN))
{
NNTestHistory();
NNExtendedTests();
quit("Analogue tests complete");
}
return;
#endif
int T, AnalogueSide;
var Limit, UnitRisk;
BarPeriod = 60;
LookBack = 181;
StartDate = 20240101;
EndDate = 20241231;
Capital = 10000.;
Hedge = 0;
MaxLong = 1;
MaxShort = 1;
if (!asset("EUR/USD"))
{
return;
}
algo("NN09");
if (is(EXITRUN))
{
NNResearchDiagnostics();
return;
}
if (is(LOOKBACK))
{
return;
}
for (T = 0; T < 180; T++)
{
NNPrices[T] = priceClose(T + 1);
}
AnalogueSide = NNFindRecurrences();
if (NNEntropy > 0.98)
{
exitLong();
exitShort();
return;
}
if (AnalogueSide > 0)
{
exitShort();
}
if (AnalogueSide < 0)
{
exitLong();
}
if (AnalogueSide == 0 || NumOpenLong + NumOpenShort > 0)
{
return;
}
if (Balance <= 0. || Equity < Balance * 0.85)
{
return;
}
if (LotAmount <= 0. || MarginCost <= 0. || PIP <= 0. || PIPCost <= 0.)
{
return;
}
Stop = 35. * PIP;
TakeProfit = 70. * PIP;
LifeTime = 4;
UnitRisk = (Stop + Spread) / PIP * PIPCost + Commission * LotAmount / 10000.;
if (UnitRisk <= 0.)
{
return;
}
Limit = min(Balance * 0.005 / UnitRisk, 2000. / LotAmount);
Limit = min(Limit, max(0., Equity - MarginVal) * 0.8 / MarginCost);
if (Limit < 1.)
{
return;
}
Lots = floor(Limit);
Margin = 0.;
Risk = 0.;
if (AnalogueSide > 0)
{
enterLong();
}
else
{
enterShort();
}
}