// 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();
}
}