// TGr05.cpp - Zorro64 Strategy DLL (C++) - Two coupled graphs for algo trading
#include <zorro.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define INF 1e30
// =============================== Graph (OO) ===============================
class WeightedGraph {
public:
int n = 0;
double* d = 0; // adjacency/shortest-path matrix (n*n)
WeightedGraph(int N) { init(N); }
~WeightedGraph() { shutdown(); }
void init(int N) {
shutdown();
n = N;
d = (double*)malloc((size_t)n*(size_t)n*sizeof(double));
if(!d) quit("OOM: WeightedGraph matrix");
reset();
}
void shutdown() {
if(d) free(d);
d = 0;
n = 0;
}
inline int pos(int r,int c) const { return r*n + c; }
void reset() {
for(int r=0;r<n;r++)
for(int c=0;c<n;c++)
d[pos(r,c)] = (r==c) ? 0.0 : INF;
}
// Floyd-Warshall shortest paths
void allPairsShortest() {
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++) {
double cand = d[pos(i,k)] + d[pos(k,j)];
if(cand < d[pos(i,j)]) d[pos(i,j)] = cand;
}
}
// Wiener-like sum over unordered pairs (symmetrized)
double wienerUndirectedLike() const {
double W = 0.0;
for(int i=0;i<n;i++)
for(int j=i+1;j<n;j++) {
double dij = d[pos(i,j)];
double dji = d[pos(j,i)];
W += 0.5*(dij + dji);
}
return W;
}
void dump(const char* title) const {
printf("\n%s", title);
for(int r=0;r<n;r++) {
printf("\n");
for(int c=0;c<n;c++) {
double v = d[pos(r,c)];
if(v > 1e20) printf(" INF ");
else printf("%5.2f ", v);
}
}
}
};
// ========================== Graph A: Markov State Graph ===================
// Edge weight = -log(p_ij) (probability -> distance)
class RegimeMarkovGraph {
public:
WeightedGraph G;
RegimeMarkovGraph(int states) : G(states) {}
static double probToDist(double p) {
if(p <= 0.0) return INF;
if(p > 1.0) p = 1.0;
return -log(p);
}
void setTransitionProb(int i,int j,double p) {
G.d[G.pos(i,j)] = probToDist(p);
}
// Example presets: directional vs choppy (toy)
void buildDirectional4() {
G.reset();
setTransitionProb(0,0,0.65); setTransitionProb(0,1,0.30); setTransitionProb(0,2,0.04); setTransitionProb(0,3,0.01);
setTransitionProb(1,0,0.25); setTransitionProb(1,1,0.60); setTransitionProb(1,2,0.12); setTransitionProb(1,3,0.03);
setTransitionProb(2,0,0.03); setTransitionProb(2,1,0.12); setTransitionProb(2,2,0.60); setTransitionProb(2,3,0.25);
setTransitionProb(3,0,0.01); setTransitionProb(3,1,0.04); setTransitionProb(3,2,0.30); setTransitionProb(3,3,0.65);
}
void buildChoppy4() {
G.reset();
setTransitionProb(0,0,0.28); setTransitionProb(0,1,0.24); setTransitionProb(0,2,0.25); setTransitionProb(0,3,0.23);
setTransitionProb(1,0,0.23); setTransitionProb(1,1,0.27); setTransitionProb(1,2,0.26); setTransitionProb(1,3,0.24);
setTransitionProb(2,0,0.24); setTransitionProb(2,1,0.26); setTransitionProb(2,2,0.27); setTransitionProb(2,3,0.23);
setTransitionProb(3,0,0.25); setTransitionProb(3,1,0.23); setTransitionProb(3,2,0.24); setTransitionProb(3,3,0.28);
}
// Compactness: lower Wiener => more compact; convert to a score in [0,1]
double compactnessScore() {
G.allPairsShortest();
double W = G.wienerUndirectedLike();
// simple squash: smaller W => larger score
return 1.0/(1.0 + W);
}
};
// ========================== Graph B: Asset Relationship Graph =============
// Edge weight = 1 - |corr| (strong corr => short distance)
class AssetCorrelationGraph {
public:
WeightedGraph G;
AssetCorrelationGraph(int assets) : G(assets) {}
static double corrToDist(double corr) {
double a = fabs(corr);
if(a > 1.0) a = 1.0;
return 1.0 - a; // in [0,1]
}
void setCorr(int i,int j,double corr) {
double w = corrToDist(corr);
G.d[G.pos(i,j)] = w;
G.d[G.pos(j,i)] = w;
}
// Example 3-asset correlation structure (toy)
// 0=EUR/USD, 1=GBP/USD, 2=USD/JPY
void buildToyFX() {
G.reset();
// self already 0
setCorr(0,1,0.85); // EURUSD ~ GBPUSD high positive corr -> short distance
setCorr(0,2,-0.30); // EURUSD vs USDJPY mild negative -> larger distance
setCorr(1,2,-0.25); // GBPUSD vs USDJPY mild negative
}
// Coupling: lower Wiener => assets tightly coupled; convert to risk penalty in [0,1]
double couplingPenalty() {
G.allPairsShortest();
double W = G.wienerUndirectedLike();
// smaller W => higher coupling => higher penalty; invert & squash
return 1.0/(1.0 + W);
}
};
// ========================== Strategy: Coupled Two-Graph Logic =============
class TwoGraphStrategy {
public:
// Hyperparameters
double alpha = 2.0; // weight for regime compactness
double beta = 1.5; // weight for asset coupling penalty
double baseRisk = 1.0;
// Graphs
RegimeMarkovGraph RG;
AssetCorrelationGraph AG;
TwoGraphStrategy() : RG(4), AG(3) {}
static double sigmoid(double x) {
// stable-ish sigmoid
if(x > 30) return 1.0;
if(x < -30) return 0.0;
return 1.0/(1.0 + exp(-x));
}
// In a real system:
// - RG transitions come from online Markov counts over price-action states
// - AG correlations come from rolling returns correlations of assets
// Here: toy graphs to demonstrate the coupling logic.
void buildToyInputs(int useDirectional) {
if(useDirectional) RG.buildDirectional4();
else RG.buildChoppy4();
AG.buildToyFX();
}
// Coupling between two graphs in "mathematical context":
// we treat RG.compactness as signal quality and AG.coupling as diversification risk.
double riskThrottle() {
double comp = RG.compactnessScore(); // higher = better / more predictable
double coup = AG.couplingPenalty(); // higher = more coupled / more dangerous
// combined score -> throttle in [0,1]
double x = alpha*comp - beta*coup;
return sigmoid(x);
}
void explain(double thr) {
printf("\n\n[TwoGraph] Regime compactness score = %.4f", RG.compactnessScore());
printf("\n[TwoGraph] Asset coupling penalty = %.4f", AG.couplingPenalty());
printf("\n[TwoGraph] Risk throttle (0..1) = %.4f", thr);
printf("\n[TwoGraph] Suggested Lots scale = %.3f", baseRisk * (0.25 + 0.75*thr));
}
// Demo run: compare two regimes (directional vs choppy) under same asset coupling
void demo() {
// Case A: directional
buildToyInputs(1);
double thrA = riskThrottle();
printf("\n=== CASE A: Directional regime ===");
RG.G.dump("\nRegime graph shortest distances:");
AG.G.dump("\nAsset graph shortest distances:");
explain(thrA);
// Case B: choppy
buildToyInputs(0);
double thrB = riskThrottle();
printf("\n\n=== CASE B: Choppy regime ===");
RG.G.dump("\nRegime graph shortest distances:");
AG.G.dump("\nAsset graph shortest distances:");
explain(thrB);
printf("\n\nInterpretation:");
printf("\n- If regime transitions are compact (predictable), throttle increases.");
printf("\n- If assets are tightly coupled (low diversification), throttle decreases.");
printf("\n- The trading engine can use throttle to scale order size / aggression.");
}
};
// =============================== Entry ===================================
static TwoGraphStrategy* S = 0;
DLLFUNC void run()
{
if(is(INITRUN))
{
if(!S) S = new TwoGraphStrategy();
S->demo();
quit("Done.");
}
}