Gate-and-Field Adaptive Engine (GFAE)

A. Finite language of situations
Each moment is mapped to a single symbol from a small alphabet. From experience, the system remembers which symbols tend to follow which, and how concentrated those follow-ups are. Two summaries are read each moment: a lean (which way the next step tilts) and a clarity (how decisive that tilt is). They serve as a gate—sometimes permissive, sometimes not.

B. Continuous field of influences
Alongside the gate runs a smooth field of interacting elements. Each element updates by blending:

a trace of itself, a couple of neighbor signals passed through simple bends, a soft background rhythm spanning slow to fast, coarse crowd summaries, a touch of recent change, and a bias toward kindred elements.

All ingredients are bounded; attention is a scarce resource shared proportionally.

C. Periodic seat-reshaping
At appointed intervals the system revisits who listens to whom, how much weight each path receives, and which bends are in play. Preference goes to regular, well-behaved parts, kindred pairings along the rhythm ladder, and compact formulas. The structure molts rather than resets: same scaffold, refreshed connections.

D. Permission meets timing
Actions arise only when the gate’s lean is convincing and the field’s rhythm agrees. The field then chooses the when and the how-much.

E. Self-explanation
As it runs, the system writes short, human-readable snippets: the current symbol, the gate’s lean and clarity, and concise sketches of how elements combined their inputs. The result is a living ledger of conditions and responses.

F. What emerges
Coherence without uniformity: clusters coordinate when the rhythm invites them, solos recede when clarity fades, and adaptability is maintained through small, proportional adjustments spread across the whole.


Code
// ======================================================================
// Markov-augmented Harmonic D-Tree Engine (Candlestick 122-directional)
// ======================================================================

// ================= USER CONFIG =================
#define ASSET_SYMBOL   "EUR/USD"   // symbol to trade
#define ALGO_NAME      "Alpha10b"  // algo tag (keeps models/files separated)

// Markov gating thresholds
#define MC_ACT         0.30        // min |CDL| ([-1..1]) to mark a pattern active
#define PBULL_LONG_TH  0.60        // Markov gate for long entries
#define PBULL_SHORT_TH 0.40        // Markov gate for short entries

// ================= ENGINE PARAMETERS =================
#define MAX_BRANCHES    3
#define MAX_DEPTH       4
#define NWIN            256
#define NET_EQNS        100
#define DEGREE          4
#define KPROJ           16
#define REWIRE_EVERY    127
#define LOG_EVERY       1

// DTREE-driven rewiring candidates per neighbor slot
#define CAND_NEIGH      8

// ---- DTREE feature sizes (extended with Markov features) ----
#define ADV_EQ_NF       12
#define ADV_PAIR_NF     12

// ================= Candles ? 122-state Markov =================
#define MC_NPAT    61
#define MC_STATES  (1 + 2*MC_NPAT)  // 0=NONE, 1..122 directional
#define MC_NONE    0
#define MC_LAPLACE 1.0

// ---------- helpers ----------
var clamp01(var x){ if(x<0) return 0; if(x>1) return 1; return x; }

int isInvalid(var x)
{
  if(x != x) return 1;                // NaN
  if(x > 1e100 || x < -1e100) return 1; // ±INF or astronomic values
  return 0;
}

var safeSig(var x){
  if(x != x) return 0;            // NaN -> 0
  if(x >  999.) return  999.;
  if(x < -999.) return -999.;
  return x;
}

// ========== Heuristic 61-candle feature builder ==========
int buildCDL_TA61(var* out, string* names)
{
  int i; for(i=0;i<MC_NPAT;i++){ out[i]=0; if(names) names[i]="UNUSED"; }

  var O = priceOpen();
  var H = priceHigh();
  var L = priceLow();
  var C = priceClose();

  var rng = H - L; if(rng <= 0) rng = 1e-8;
  var body = C - O;
  var dir  = ifelse(body >= 0, 1.0, -1.0);
  var bodyFrac  = clamp(body/rng, -1, 1);                  // [-1..1]
  var upperFrac = clamp01( (H - max(O,C)) / rng );         // [0..1]
  var lowerFrac = clamp01( (min(O,C) - L) / rng );         // [0..1]
  var absBody   = abs(body)/rng;                           // [0..1]

  // 0: body direction & size
  out[0] = bodyFrac; if(names) names[0] = "BODY";

  // 1..2: upper/lower dominance (signed)
  out[1] = clamp( upperFrac - lowerFrac, -1, 1 ); if(names) names[1] = "UPPER_DOM";
  out[2] = clamp( lowerFrac - upperFrac, -1, 1 ); if(names) names[2] = "LOWER_DOM";

  // 3: doji-ish (very small body), signed by direction
  var dojiT = 0, thresh = 0.10;
  if(absBody < thresh) dojiT = 1.0 - absBody/thresh;   // 0..1
  out[3] = dir * dojiT; if(names) names[3] = "DOJI";

  // 4: marubozu-ish (both shadows tiny), signed by direction
  var shadowSum = upperFrac + lowerFrac;
  var maru = 0; if(shadowSum < 0.10) maru = 1.0 - shadowSum/0.10;
  out[4] = dir * clamp01(maru); if(names) names[4] = "MARUBOZU";

  // 5: hammer-ish (long lower, tiny upper)
  var hamm = 0; if(lowerFrac > 0.60 && upperFrac < 0.10) hamm = (lowerFrac - 0.60)/0.40;
  out[5] = dir * clamp01(hamm); if(names) names[5] = "HAMMER";

  // 6: shooting-star-ish (long upper, tiny lower), bearish by shape
  var star = 0; if(upperFrac > 0.60 && lowerFrac < 0.10) star = (upperFrac - 0.60)/0.40;
  out[6] = -clamp01(star); if(names) names[6] = "SHOOTING";

  // 7: long body strength (signed)
  var longB = 0; if(absBody > 0.70) longB = (absBody - 0.70)/0.30;
  out[7] = dir * clamp01(longB); if(names) names[7] = "LONG_BODY";

  // 8: small body (spinning top-ish)
  out[8] = dir * (1.0 - absBody); if(names) names[8] = "SPIN_TOP";

  // 9: momentum-ish scalar from body size (signed)
  out[9] = dir * (2.0*absBody - 1.0); if(names) names[9] = "BODY_MOM";

  // 10..60 left as zero/UNUSED
  return 61;
}

// ===== Markov storage =====
#define MC_IDX(s,t) ((s)*MC_STATES + (t))
static int*  MC_Count;        // size MC_STATES*MC_STATES
static int*  MC_RowSum;       // size MC_STATES
static int   MC_Prev = -1;
static int   MC_Cur  = 0;
static var   MC_PBullNext = 0.5;
static var   MC_Entropy   = 0.0;
static string MC_Names[MC_NPAT];

void MC_alloc()
{
  int i;
  MC_Count  = (int*)malloc(MC_STATES*MC_STATES*sizeof(int));
  MC_RowSum = (int*)malloc(MC_STATES*sizeof(int));
  for(i=0;i<MC_STATES*MC_STATES;i++) MC_Count[i]=0;
  for(i=0;i<MC_STATES;i++) MC_RowSum[i]=0;
  MC_Prev = -1; MC_Cur = 0; MC_PBullNext = 0.5; MC_Entropy = 0.;
}
void MC_free(){ if(MC_Count){free(MC_Count);MC_Count=0;} if(MC_RowSum){free(MC_RowSum);MC_RowSum=0;} }

int MC_stateFromCDL(var* cdl /*len=61*/, var thr)
{
  int i, best=-1; var besta=0;
  for(i=0;i<MC_NPAT;i++){ var a=abs(cdl[i]); if(a>besta){ besta=a; best=i; } }
  if(best<0) return MC_NONE;
  if(besta < thr) return MC_NONE;
  int bull = (cdl[best] > 0);
  return 1 + 2*best + bull;
}
int MC_indexFromState(int s){ if(s<=0) return -1; return (s-1)/2; }
int MC_isBull(int s){ if(s<=0) return 0; return ((s-1)%2)==1; }

void MC_update(int sPrev,int sCur)
{
  if(sPrev<0) return;
  MC_Count[MC_IDX(sPrev,sCur)] += 1;
  MC_RowSum[sPrev]             += 1;
}

var MC_prob(int s,int t)
{
  var num = (var)MC_Count[MC_IDX(s,t)] + MC_LAPLACE;
  var den = (var)MC_RowSum[s] + MC_LAPLACE*MC_STATES;
  if(den<=0) return 1.0/MC_STATES;
  return num/den;
}

var MC_nextBullishProb(int s)
{
  if(s<0) return 0.5;
  int t; var pBull=0, pTot=0;
  for(t=1;t<MC_STATES;t++){ var p=MC_prob(s,t); pTot += p; if(MC_isBull(t)) pBull += p; }
  if(pTot<=0) return 0.5;
  return pBull/pTot;
}

var MC_rowEntropy01(int s)
{
  if(s<0) return 1.0;
  int t; var H=0, Z=0;
  for(t=1;t<MC_STATES;t++){ var p=MC_prob(s,t); Z+=p; }
  if(Z<=0) return 1.0;
  for(t=1;t<MC_STATES;t++){
    var p=MC_prob(s,t)/Z;
    if(p>0) H += -p*log(p);
  }
  var Hmax = log(MC_STATES-1);
  if(Hmax<=0) return 0;
  return H/Hmax;
}

// ================= HARMONIC D-TREE (engine) =================
typedef struct Node { var v; var r; void* c; int n; int d; } Node;
Node* Root;
Node** G_TreeIdx;  int G_TreeN; int G_TreeCap; var G_DTreeExp;

// ------- helpers (built-ins used) -------
int randint(int lo,int hi){ return lo + (int)random(hi - lo + 1); }      // [lo..hi]
var randu(var a,var b){ return a + random(b - a); }                       // [a..b)
var randsign(){ return ifelse(random(1) < 0.5, -1.0, 1.0); }
var mapUnit(var u,var lo,var hi){ u = clamp(u,-1.,1.); var t=0.5*(u+1.0); return lo + t*(hi-lo); }

void pushTreeNode(Node* u){ if(G_TreeN < G_TreeCap) G_TreeIdx[G_TreeN++] = u; }
void indexTreeDFS(Node* u){ if(!u) return; pushTreeNode(u); int i; for(i=0;i<u->n;i++) indexTreeDFS(((Node**)u->c)[i]); }

Node* createNode(int depth)
{
  Node* u = (Node*)malloc(sizeof(Node));
  u->v = 2*random(1)-1;                             // [-1..1)
  u->r = 0.01 + 0.02*depth + random(1)*0.005;       // small positive
  u->d = depth;
  if(depth > 0){
    u->n = randint(1, MAX_BRANCHES);
    u->c = malloc(u->n * sizeof(void*));
    int i; for(i=0;i<u->n;i++) ((Node**)u->c)[i] = createNode(depth - 1);
  } else { u->n = 0; u->c = 0; }
  return u;
}
var evaluateNode(Node* u)
{
  if(!u) return 0;
  var sum=0; int i; for(i=0;i<u->n;i++) sum += evaluateNode(((Node**)u->c)[i]);
  var phase  = sin(u->r * Bar + sum);
  var weight = 1.0 / pow(u->d + 1, G_DTreeExp);
  u->v = (1 - weight)*u->v + weight*phase;
  return u->v;
}
int countNodes(Node* u){ if(!u) return 0; int c=1,i; for(i=0;i<u->n;i++) c += countNodes(((Node**)u->c)[i]); return c; }
void freeTree(Node* u){ if(!u) return; int i; for(i=0;i<u->n;i++) freeTree(((Node**)u->c)[i]); if(u->c) free(u->c); free(u); }

// =========== NETWORK STATE & COEFFICIENTS ===========
int   G_N  = NET_EQNS;
int   G_D  = DEGREE;
int   G_K  = KPROJ;

var*  G_State; var*  G_Prev; var*  G_Vel;
int*  G_Adj;  var*   G_RP;   var*  G_Z;

int*  G_Mode;
var*  G_WSelf; var*  G_WN1; var*  G_WN2; var*  G_WGlob1; var*  G_WGlob2; var*  G_WMom; var*  G_WTree; var*  G_WAdv;

var*  A1x;  var*  A1lam;  var*  A1mean;  var*  A1E;  var*  A1P;  var*  A1i;  var*  A1c;
var*  A2x;  var*  A2lam;  var*  A2mean;  var*  A2E;  var*  A2P;  var*  A2i;  var*  A2c;

var*  G1mean; var*  G1E; var*  G2P; var*  G2lam;

var*  G_TreeTerm; int*  G_TopEq; var*  G_TopW; int*  G_EqTreeId; var*  TAlpha; var*  TBeta;
var*  G_Pred; var*  G_AdvScore;

var*  G_PropRaw; var*  G_Prop;
string* G_Sym;

// Markov features exposed to DTREE
var G_MCF_PBull, G_MCF_Entropy, G_MCF_State;

// epoch/context & feedback
int    G_Epoch = 0;
int    G_CtxID = 0;
var    G_FB_A = 0.7;
var    G_FB_B = 0.3;

// ---------- predictability from D-tree ----------
var nodePredictability(Node* t)
{
  if(!t) return 0.5;
  var disp=0; int n=t->n, i;
  for(i=0;i<n;i++){ Node* c=((Node**)t->c)[i]; disp += abs(c->v - t->v); }
  if(n>0) disp /= n;
  var depthFac = 1.0/(1+t->d);
  var rateBase = 0.01 + 0.02*t->d;
  var rateFac  = exp(-25.0*abs(t->r - rateBase));
  var p = 0.5*(depthFac + rateFac);
  p = 0.5*p + 0.5*(1.0/(1.0 + disp));
  return clamp(p,0,1);
}

// filenames
void buildEqFileName(int idx, char* outName /*>=64*/) { strcpy(outName, strf("Log\\%s_eq_%03i.csv", ALGO_NAME, idx)); }

// --------- allocation ----------
void allocateNet()
{
  int N=G_N, D=G_D, K=G_K;
  G_State=(var*)malloc(N*sizeof(var));  G_Prev=(var*)malloc(N*sizeof(var));  G_Vel=(var*)malloc(N*sizeof(var));
  G_Adj=(int*)malloc(N*D*sizeof(int));
  G_RP=(var*)malloc(K*N*sizeof(var));   G_Z=(var*)malloc(K*sizeof(var));
  G_Mode=(int*)malloc(N*sizeof(int));
  G_WSelf=(var*)malloc(N*sizeof(var));  G_WN1=(var*)malloc(N*sizeof(var));   G_WN2=(var*)malloc(N*sizeof(var));
  G_WGlob1=(var*)malloc(N*sizeof(var)); G_WGlob2=(var*)malloc(N*sizeof(var));
  G_WMom=(var*)malloc(N*sizeof(var));   G_WTree=(var*)malloc(N*sizeof(var)); G_WAdv=(var*)malloc(N*sizeof(var));
  A1x=(var*)malloc(N*sizeof(var)); A1lam=(var*)malloc(N*sizeof(var)); A1mean=(var*)malloc(N*sizeof(var));
  A1E=(var*)malloc(N*sizeof(var)); A1P=(var*)malloc(N*sizeof(var));   A1i=(var*)malloc(N*sizeof(var)); A1c=(var*)malloc(N*sizeof(var));
  A2x=(var*)malloc(N*sizeof(var)); A2lam=(var*)malloc(N*sizeof(var)); A2mean=(var*)malloc(N*sizeof(var));
  A2E=(var*)malloc(N*sizeof(var)); A2P=(var*)malloc(N*sizeof(var));   A2i=(var*)malloc(N*sizeof(var)); A2c=(var*)malloc(N*sizeof(var));
  G1mean=(var*)malloc(N*sizeof(var)); G1E=(var*)malloc(N*sizeof(var));
  G2P=(var*)malloc(N*sizeof(var));    G2lam=(var*)malloc(N*sizeof(var));
  G_TreeTerm=(var*)malloc(N*sizeof(var)); G_TopEq=(int*)malloc(N*sizeof(int)); G_TopW=(var*)malloc(N*sizeof(var));
  TAlpha=(var*)malloc(N*sizeof(var));     TBeta=(var*)malloc(N*sizeof(var));
  G_Pred=(var*)malloc(N*sizeof(var)); G_AdvScore=(var*)malloc(N*sizeof(var));
  G_PropRaw=(var*)malloc(N*sizeof(var));  G_Prop=(var*)malloc(N*sizeof(var));
  G_Sym=(string*)malloc(N*sizeof(string));
  G_TreeCap=512; G_TreeIdx=(Node**)malloc(G_TreeCap*sizeof(Node*)); G_TreeN=0;
  G_EqTreeId=(int*)malloc(N*sizeof(int));

  int i;
  for(i=0;i<N;i++){
    G_State[i]=2*random(1)-1; G_Prev[i]=G_State[i]; G_Vel[i]=0;
    G_Mode[i]=0;
    G_WSelf[i]=0.5; G_WN1[i]=0.2; G_WN2[i]=0.2; G_WGlob1[i]=0.1; G_WGlob2[i]=0.1; G_WMom[i]=0.05; G_WTree[i]=0.15; G_WAdv[i]=0.15;
    A1x[i]=1; A1lam[i]=0.1; A1mean[i]=0; A1E[i]=0; A1P[i]=0; A1i[i]=0; A1c[i]=0;
    A2x[i]=1; A2lam[i]=0.1; A2mean[i]=0; A2E[i]=0; A2P[i]=0; A2i[i]=0; A2c[i]=0;
    G1mean[i]=1.0; G1E[i]=0.001; G2P[i]=0.6; G2lam[i]=0.3;
    TAlpha[i]=0.8; TBeta[i]=25.0;
    G_TreeTerm[i]=0; G_TopEq[i]=-1; G_TopW[i]=0;
    G_Pred[i]=0.5;   G_AdvScore[i]=0;
    G_PropRaw[i]=1;  G_Prop[i]=1.0/G_N;
    G_Sym[i]=(char*)malloc(1024); strcpy(G_Sym[i],"");
  }
}
void freeNet()
{
  int i;
  if(G_State)free(G_State); if(G_Prev)free(G_Prev); if(G_Vel)free(G_Vel);
  if(G_Adj)free(G_Adj); if(G_RP)free(G_RP); if(G_Z)free(G_Z);
  if(G_Mode)free(G_Mode); if(G_WSelf)free(G_WSelf); if(G_WN1)free(G_WN1); if(G_WN2)free(G_WN2);
  if(G_WGlob1)free(G_WGlob1); if(G_WGlob2)free(G_WGlob2); if(G_WMom)free(G_WMom);
  if(G_WTree)free(G_WTree); if(G_WAdv)free(G_WAdv);
  if(A1x)free(A1x); if(A1lam)free(A1lam); if(A1mean)free(A1mean); if(A1E)free(A1E); if(A1P)free(A1P); if(A1i)free(A1i); if(A1c)free(A1c);
  if(A2x)free(A2x); if(A2lam)free(A2lam); if(A2mean)free(A2mean); if(A2E)free(A2E); if(A2P)free(A2P); if(A2i)free(A2i); if(A2c)free(A2c);
  if(G1mean)free(G1mean); if(G1E)free(G1E); if(G2P)free(G2P); if(G2lam)free(G2lam);
  if(G_TreeTerm)free(G_TreeTerm); if(G_TopEq)free(G_TopEq); if(G_TopW)free(G_TopW);
  if(TAlpha)free(TAlpha); if(TBeta)free(TBeta);
  if(G_Pred)free(G_Pred); if(G_AdvScore)free(G_AdvScore);
  if(G_PropRaw)free(G_PropRaw); if(G_Prop)free(G_Prop);
  if(G_Sym){ for(i=0;i<G_N;i++) if(G_Sym[i]) free(G_Sym[i]); free(G_Sym); }
  if(G_TreeIdx)free(G_TreeIdx); if(G_EqTreeId)free(G_EqTreeId);
}

// --------- random projection ----------
void randomizeRP(){ int K=G_K,N=G_N,k,j; for(k=0;k<K;k++) for(j=0;j<N;j++) G_RP[k*N+j]=ifelse(random(1)<0.5,-1.0,1.0); }
void computeProjection(){ int K=G_K,N=G_N,k,j; for(k=0;k<K;k++){ var acc=0; for(j=0;j<N;j++) acc+=G_RP[k*N+j]*(G_State[j]*G_State[j]); G_Z[k]=acc; }}

// --------- build features for DTREE (EXTENDED with Markov) ----------
void buildEqFeatures(int i, var lambda, var mean, var energy, var power, var* S /*ADV_EQ_NF*/)
{
  Node* t=G_TreeIdx[G_EqTreeId[i]];
  S[0]=safeSig(G_State[i]);   S[1]=safeSig(mean);     S[2]=safeSig(power); S[3]=safeSig(energy);
  S[4]=safeSig(lambda);       S[5]=safeSig(G_Pred[i]); S[6]=safeSig(t->d);  S[7]=safeSig(t->r);
  S[8]=safeSig(G_TreeTerm[i]); S[9]=safeSig(G_Mode[i]);
  S[10]=safeSig(G_MCF_PBull);  S[11]=safeSig(G_MCF_Entropy);
}
void buildPairFeatures(int i,int j, var lambda, var mean, var energy, var power, var* P /*ADV_PAIR_NF*/)
{
  Node* ti=G_TreeIdx[G_EqTreeId[i]];
  Node* tj=G_TreeIdx[G_EqTreeId[j]];
  P[0]=safeSig(G_State[i]); P[1]=safeSig(G_State[j]);
  P[2]=safeSig(ti->d);      P[3]=safeSig(tj->d);
  P[4]=safeSig(ti->r);      P[5]=safeSig(tj->r);
  P[6]=safeSig(abs(P[2]-P[3])); P[7]=safeSig(abs(P[4]-P[5]));
  P[8]=safeSig(G_Pred[i]*G_Pred[j]);
  P[9]=safeSig(lambda); P[10]=safeSig(mean); P[11]=safeSig(power);
}

// --------- DTREE advice wrappers ----------
var adviseEq(int i, var lambda, var mean, var energy, var power)
{
  var S[ADV_EQ_NF]; buildEqFeatures(i,lambda,mean,energy,power,S);
  var a = adviseLong(DTREE+RETURNS, 0, S, ADV_EQ_NF); // RETURNS => use next trade return as target in Train
  return a/100.;
}
var advisePair(int i,int j, var lambda, var mean, var energy, var power)
{
  var P[ADV_PAIR_NF]; buildPairFeatures(i,j,lambda,mean,energy,power,P);
  var a = adviseLong(DTREE+RETURNS, 0, P, ADV_PAIR_NF);
  return a/100.;
}

// --------- DTREE-driven adjacency selection ----------
void rewireAdjacency_DTREE(var lambda, var mean, var energy, var power)
{
  int N=G_N, D=G_D, i, d, c, best, cand;
  for(i=0;i<N;i++){
    for(d=0; d<D; d++){
      var bestScore = -2; best = -1;
      for(c=0;c<CAND_NEIGH;c++){
        cand = randint(0,N-1);
        if(cand==i) continue;
        int clash=0, k; for(k=0;k<d;k++) if(G_Adj[i*D+k]==cand){clash=1; break;}
        if(clash) continue;
        var s = advisePair(i,cand,lambda,mean,energy,power);
        if(s > bestScore){ bestScore=s; best=cand; }
      }
      if(best<0){ do{ best = randint(0,N-1);} while(best==i); }
      G_Adj[i*D + d] = best;
    }
  }
}

// --------- DTREE-created coefficients, modes & proportions ----------
void synthesizeEquationFromDTREE(int i, var lambda, var mean, var energy, var power)
{
  var a_mode = adviseEq(i,lambda,mean,energy,power);
  G_Mode[i] = (int)(abs(a_mode*1000)) & 3;

  var a_wself = adviseEq(i,lambda,mean,energy,power);
  var a_wn1   = adviseEq(i,lambda,mean,energy,power);
  var a_wn2   = adviseEq(i,lambda,mean,energy,power);
  var a_g1    = adviseEq(i,lambda,mean,energy,power);
  var a_g2    = adviseEq(i,lambda,mean,energy,power);
  var a_mom   = adviseEq(i,lambda,mean,energy,power);
  var a_tree  = adviseEq(i,lambda,mean,energy,power);
  var a_adv   = adviseEq(i,lambda,mean,energy,power);

  G_WSelf[i]  = mapUnit(a_wself, 0.15, 0.85);
  G_WN1[i]    = mapUnit(a_wn1,   0.05, 0.35);
  G_WN2[i]    = mapUnit(a_wn2,   0.05, 0.35);
  G_WGlob1[i] = mapUnit(a_g1,    0.05, 0.30);
  G_WGlob2[i] = mapUnit(a_g2,    0.05, 0.30);
  G_WMom[i]   = mapUnit(a_mom,   0.02, 0.15);
  G_WTree[i]  = mapUnit(a_tree,  0.05, 0.35);
  G_WAdv[i]   = mapUnit(a_adv,   0.05, 0.35);

  var a1=adviseEq(i,lambda,mean,energy,power);
  var a2=adviseEq(i,lambda,mean,energy,power);
  var a3=adviseEq(i,lambda,mean,energy,power);
  var a4=adviseEq(i,lambda,mean,energy,power);
  var a5=adviseEq(i,lambda,mean,energy,power);
  var a6=adviseEq(i,lambda,mean,energy,power);
  var a7=adviseEq(i,lambda,mean,energy,power);

  A1x[i]   = randsign()*mapUnit(a1, 0.6, 1.2);
  A1lam[i] = randsign()*mapUnit(a2, 0.05,0.35);
  A1mean[i]= mapUnit(a3,-0.30,0.30);
  A1E[i]   = mapUnit(a4,-0.0015,0.0015);
  A1P[i]   = mapUnit(a5,-0.30,0.30);
  A1i[i]   = mapUnit(a6,-0.02,0.02);
  A1c[i]   = mapUnit(a7,-0.20,0.20);

  var b1=adviseEq(i,lambda,mean,energy,power);
  var b2=adviseEq(i,lambda,mean,energy,power);
  var b3=adviseEq(i,lambda,mean,energy,power);
  var b4=adviseEq(i,lambda,mean,energy,power);
  var b5=adviseEq(i,lambda,mean,energy,power);
  var b6=adviseEq(i,lambda,mean,energy,power);
  var b7=adviseEq(i,lambda,mean,energy,power);

  A2x[i]   = randsign()*mapUnit(b1, 0.6, 1.2);
  A2lam[i] = randsign()*mapUnit(b2, 0.05,0.35);
  A2mean[i]= mapUnit(b3,-0.30,0.30);
  A2E[i]   = mapUnit(b4,-0.0015,0.0015);
  A2P[i]   = mapUnit(b5,-0.30,0.30);
  A2i[i]   = mapUnit(b6,-0.02,0.02);
  A2c[i]   = mapUnit(b7,-0.20,0.20);

  var c1=adviseEq(i,lambda,mean,energy,power);
  var c2=adviseEq(i,lambda,mean,energy,power);
  var d1=adviseEq(i,lambda,mean,energy,power);
  var d2=adviseEq(i,lambda,mean,energy,power);
  G1mean[i] = mapUnit(c1, 0.4, 1.6);
  G1E[i]    = mapUnit(c2,-0.004,0.004);
  G2P[i]    = mapUnit(d1, 0.1, 1.2);
  G2lam[i]  = mapUnit(d2, 0.05,0.7);

  var e1=adviseEq(i,lambda,mean,energy,power);
  var e2=adviseEq(i,lambda,mean,energy,power);
  TAlpha[i] = mapUnit(e1, 0.3, 1.5);
  TBeta[i]  = mapUnit(e2, 6.0, 50.0);

  var p = adviseEq(i,lambda,mean,energy,power);
  G_PropRaw[i] = 0.01 + 0.99 * (0.5*(p+1.0));
}

void normalizeProportions()
{
  int N=G_N,i; var s=0; for(i=0;i<N;i++) s += G_PropRaw[i];
  if(s<=0) { for(i=0;i<N;i++) G_Prop[i] = 1.0/N; return; }
  for(i=0;i<N;i++) G_Prop[i] = G_PropRaw[i]/s;
}

// --------- DTree proportional coupling ----------
var dtreeTerm(int i, int* outTopEq, var* outTopW)
{
  int N=G_N,j;
  int tid_i=G_EqTreeId[i]; Node* ti=G_TreeIdx[tid_i]; int di=ti->d; var ri=ti->r;
  var alpha=TAlpha[i], beta=TBeta[i];

  var sumw=0, acc=0, bestW=-1; int bestJ=-1;
  for(j=0;j<N;j++){
    if(j==i) continue;
    int tid_j=G_EqTreeId[j]; Node* tj=G_TreeIdx[tid_j]; int dj=tj->d; var rj=tj->r;

    var w = exp(-alpha*abs(di-dj)) * exp(-beta*abs(ri-rj));
    var predBoost = 0.5 + 0.5*(G_Pred[i]*G_Pred[j]);
    var propBoost = 0.5 + 0.5*( (G_Prop[i] + G_Prop[j]) );
    w *= predBoost * propBoost;

    var pairAdv = advisePair(i,j,0,0,0,0);
    w *= (0.75 + 0.25*(0.5*(pairAdv+1.0)));

    sumw += w; acc += w*G_State[j];
    if(w>bestW){bestW=w; bestJ=j;}
  }
  if(outTopEq) *outTopEq = bestJ;
  if(outTopW)  *outTopW  = ifelse(sumw>0, bestW/sumw, 0);
  if(sumw>0) return acc/sumw; return 0;
}

// --------- symbolic expression builder ----------
void buildSymbolicExpr(int i, int n1, int n2)
{
  string s = G_Sym[i]; strcpy(s,"");
  string a1 = strf("(%.3f*x[%i] + %.3f*lam + %.3f*mean + %.5f*E + %.3f*P + %.3f*i + %.3f)",
                   A1x[i], n1, A1lam[i], A1mean[i], A1E[i], A1P[i], A1i[i], A1c[i]);
  string a2 = strf("(%.3f*x[%i] + %.3f*lam + %.3f*mean + %.5f*E + %.3f*P + %.3f*i + %.3f)",
                   A2x[i], n2, A2lam[i], A2mean[i], A2E[i], A2P[i], A2i[i], A2c[i]);

  strcat(s, "x[i]_next = ");
  strcat(s, strf("%.3f*x[i] + ", G_WSelf[i]));
  if(G_Mode[i]==0){ strcat(s, strf("%.3f*sin%s + ", G_WN1[i], a1)); strcat(s, strf("%.3f*cos%s + ", G_WN2[i], a2)); }
  else if(G_Mode[i]==1){ strcat(s, strf("%.3f*tanh%s + ", G_WN1[i], a1)); strcat(s, strf("%.3f*sin%s + ", G_WN2[i], a2)); }
  else if(G_Mode[i]==2){ strcat(s, strf("%.3f*cos%s + ", G_WN1[i], a1)); strcat(s, strf("%.3f*tanh%s + ", G_WN2[i], a2)); }
  else { strcat(s, strf("%.3f*sin%s + ", G_WN1[i], a1)); strcat(s, strf("%.3f*cos%s + ", G_WN2[i], a2)); }

  strcat(s, strf("%.3f*tanh(%.3f*mean + %.5f*E) + ", G_WGlob1[i], G1mean[i], G1E[i]));
  strcat(s, strf("%.3f*sin(%.3f*P + %.3f*lam) + ",   G_WGlob2[i], G2P[i],   G2lam[i]));
  strcat(s, strf("%.3f*(x[i]-x_prev[i]) + ",         G_WMom[i]));
  strcat(s, strf("Prop[i]=%.4f; ",                    G_Prop[i]));
  strcat(s, strf("%.3f*DT(i) + ",                    G_WTree[i]));
  strcat(s, strf("%.3f*DTREE(i)",                    G_WAdv[i]  ));
}

// --------- one-time rewire init ----------
void rewireInit()
{
  randomizeRP(); computeProjection();
  G_TreeN=0; indexTreeDFS(Root);
  int i; for(i=0;i<G_N;i++) G_EqTreeId[i] = i % G_TreeN;
}

// --------- epoch rewire ----------
void rewireEpoch(var lambda, var mean, var energy, var power)
{
  int i;
  for(i=0;i<G_N;i++){ Node* t=G_TreeIdx[G_EqTreeId[i]]; G_Pred[i]=nodePredictability(t); }
  rewireAdjacency_DTREE(lambda,mean,energy,power);
  for(i=0;i<G_N;i++) synthesizeEquationFromDTREE(i,lambda,mean,energy,power);
  normalizeProportions();
  int D=G_D; int h=0; for(i=0;i<G_N*D;i++) h = (h*1315423911) ^ G_Adj[i];
  G_CtxID = (h ^ (G_Epoch<<8)) & 0x7FFFFFFF;
  for(i=0;i<G_N;i++){ int n1=G_Adj[i*G_D+0], n2=G_Adj[i*G_D+1]; buildSymbolicExpr(i,n1,n2); }
}

// --------- compact driver ----------
var projectNet()
{
  int N=G_N,i; var sum=0,sumsq=0,cross=0;
  for(i=0;i<N;i++){ sum+=G_State[i]; sumsq+=G_State[i]*G_State[i]; if(i+1<N) cross+=G_State[i]*G_State[i+1]; }
  var mean=sum/N, corr=cross/(N-1);
  return 0.6*tanh(mean + 0.001*sumsq) + 0.4*sin(corr);
}

// --------- per-bar update ----------
void updateNet(var driver, var* outMean, var* outEnergy, var* outPower, int writeMeta)
{
  int N=G_N, D=G_D, i;

  var sum=0,sumsq=0; for(i=0;i<N;i++){ sum+=G_State[i]; sumsq+=G_State[i]*G_State[i]; }
  var mean=sum/N, energy=sumsq, power=sumsq/N;

  for(i=0;i<N;i++){ Node* t=G_TreeIdx[G_EqTreeId[i]]; G_Pred[i]=nodePredictability(t); }

  for(i=0;i<N;i++){
    int n1=G_Adj[i*D+0], n2=G_Adj[i*D+1];
    var xi=G_State[i], xn1=G_State[n1], xn2=G_State[n2], mom=xi-G_Prev[i];

    int topEq=-1; var topW=0;
    var dt = dtreeTerm(i,&topEq,&topW);
    G_TreeTerm[i]=dt; G_TopEq[i]=topEq; G_TopW[i]=topW;

    var adv = adviseEq(i, driver, mean, energy, power);
    G_AdvScore[i] = adv;

    var arg1=A1x[i]*xn1 + A1lam[i]*driver + A1mean[i]*mean + A1E[i]*energy + A1P[i]*power + A1i[i]*i + A1c[i];
    var arg2=A2x[i]*xn2 + A2lam[i]*driver + A2mean[i]*mean + A2E[i]*energy + A2P[i]*power + A2i[i]*i + A2c[i];

    var nl1,nl2;
    if(G_Mode[i]==0){ nl1=sin(arg1); nl2=cos(arg2); }
    else if(G_Mode[i]==1){ nl1=tanh(arg1); nl2=sin(arg2); }
    else if(G_Mode[i]==2){ nl1=cos(arg1);  nl2=tanh(arg2); }
    else { nl1=sin(arg1); nl2=cos(arg2); }

    var glob1=tanh(G1mean[i]*mean + G1E[i]*energy);
    var glob2=sin (G2P[i]*power + G2lam[i]*driver);

    var xNew =
      G_WSelf[i]*xi +
      G_WN1[i]*nl1 +
      G_WN2[i]*nl2 +
      G_WGlob1[i]*glob1 +
      G_WGlob2[i]*glob2 +
      G_WMom[i]*mom +
      G_WTree[i]*dt +
      G_WAdv[i] *adv;
		
	 // prevent runaway values
    if(xNew != xNew) xNew = 0;       // NaN -> 0
    else {
             if(xNew > 1e6) xNew = 1e6;
             if(xNew < -1e6) xNew = -1e6;
    }

    G_Prev[i]=xi; G_Vel[i]=xNew-xi; G_State[i]=xNew;

    if(writeMeta){
      char fname[64]; buildEqFileName(i,fname);
      int tid=G_EqTreeId[i]; Node* t=G_TreeIdx[tid];
      int nn1=G_Adj[i*D+0], nn2=G_Adj[i*D+1];
      file_append(fname,
        strf("META,%i,%i,%i,%i,%i,%i,%i,%i,%.6f,Pred=%.4f,Adv=%.4f,Prop=%.6f,Mode=%i,WAdv=%.3f,WTree=%.3f,PBull=%.4f,Ent=%.4f,State=%i,\"%s\"\n",
          G_Epoch, G_CtxID, NET_EQNS, i, nn1, nn2, tid, t->d, t->r,
          G_Pred[i], G_AdvScore[i], G_Prop[i], G_Mode[i], G_WAdv[i], G_WTree[i],
          G_MCF_PBull, G_MCF_Entropy, MC_Cur, G_Sym[i]));
    }
  }
  if(outMean) *outMean=mean; if(outEnergy) *outEnergy=energy; if(outPower) *outPower=power;
}

// ----------------- MAIN -----------------
function run()
{
  // ===== required for ML training / auto-test =====
  NumWFOCycles = 5;                 // WFO is recommended for ML
  set(RULES|TESTNOW|PLOTNOW);       // generate rules; auto-test after Train
  if(Train){                        // RETURNS target = next trade's P/L
    Hedge   = 2;                    // allow simultaneous L/S during training
    LifeTime= 1;                    // 1-bar horizon for return labeling
  } else {
    MaxLong = MaxShort = 1;         // clean behavior in Test/Trade
  }

  // ===== init once =====
  static int initialized=0;
  static var lambda;
  static int fileInit=0;

  if(LookBack < NWIN) LookBack = NWIN;
  asset(ASSET_SYMBOL);
  algo(ALGO_NAME);

  if(is(INITRUN) && !initialized){
    seed(365);  // <<< ensure deterministic Train/Test advise order

    var tmp[MC_NPAT]; buildCDL_TA61(tmp, MC_Names);

    Root=createNode(MAX_DEPTH);
    allocateNet();
    MC_alloc();

    G_DTreeExp = randu(1.10,1.60);
    G_FB_A     = randu(0.60,0.85);
    G_FB_B     = 1.0 - G_FB_A;

    randomizeRP(); computeProjection();
    rewireInit();

    // First epoch synthesis
    G_Epoch = 0;
    rewireEpoch(0,0,0,0);

    // Prepare per-equation CSVs
    char fname[64]; int i;
    for(i=0;i<NET_EQNS;i++){
      buildEqFileName(i,fname);
      file_append(fname,
        "Bar,lambda,gamma,i,State,n1,n2,mean,energy,power,Vel,Mode,WAdv,WSelf,WN1,WN2,WGlob1,WGlob2,WMom,WTree,Pred,Adv,Prop,TreeTerm,TopEq,TopW,TreeId,Depth,Rate,PBull,Entropy,MCState\n");
    }
    if(!fileInit){
      file_append(strf("Log\\%s_markov.csv",ALGO_NAME),"Bar,State,PBullNext,Entropy,RowSum\n");
      fileInit=1;
    }

    // Initial META
    for(i=0;i<G_N;i++){
      int n1=G_Adj[i*G_D+0], n2=G_Adj[i*G_D+1]; int tid=G_EqTreeId[i]; Node* t=G_TreeIdx[tid];
      char fname2[64]; buildEqFileName(i,fname2);
      file_append(fname2,
        strf("META,%i,%i,%i,%i,%i,%i,%i,%i,%.6f,Pred=%.4f,Adv=%.4f,Prop=%.6f,Mode=%i,WAdv=%.3f,WTree=%.3f,PBull=%.4f,Ent=%.4f,State=%i,\"%s\"\n",
          G_Epoch, G_CtxID, NET_EQNS, i, n1, n2, tid, t->d, t->r,
          G_Pred[i], G_AdvScore[i], G_Prop[i], G_Mode[i], G_WAdv[i], G_WTree[i],
          G_MCF_PBull, G_MCF_Entropy, MC_Cur, G_Sym[i]));
    }
    initialized=1;
    printf("\nRoot nodes: %i | Net equations: %i (deg=%i, kproj=%i)", countNodes(Root), G_N, G_D, G_K);
  }

  // ====== Per bar: Candles ? Markov
  static var CDL[MC_NPAT];
  buildCDL_TA61(CDL,0);
  MC_Cur = MC_stateFromCDL(CDL, MC_ACT);
  if(Bar > LookBack) MC_update(MC_Prev, MC_Cur);
  MC_Prev = MC_Cur;

  MC_PBullNext = MC_nextBullishProb(MC_Cur);
  MC_Entropy   = MC_rowEntropy01(MC_Cur);

  // expose global Markov features
  G_MCF_PBull   = MC_PBullNext;
  G_MCF_Entropy = MC_Entropy;
  G_MCF_State   = (var)MC_Cur;

  // ====== Tree driver lambda
  lambda = evaluateNode(Root);

  // Rewire epoch?
  int doRewire = ((Bar % REWIRE_EVERY) == 0);
  if(doRewire){
    G_Epoch++;
    int i; var sum=0; for(i=0;i<G_N;i++) sum += G_State[i];
    var mean = sum/G_N;
    var energy=0; for(i=0;i<G_N;i++) energy += G_State[i]*G_State[i];
    var power = energy/G_N;
    rewireEpoch(lambda,mean,energy,power);
  }

  // Update net this bar (write META only if rewired)
  var meanB, energyB, powerB;
  updateNet(lambda, &meanB, &energyB, &powerB, doRewire);

  // Feedback blend
  var gamma = projectNet();
  lambda = G_FB_A*lambda + G_FB_B*gamma;

  // --- safe plotting (after LookBack only) ---
if(!is(LOOKBACK))
{
  var lam = safeSig(lambda);
  var gam = safeSig(gamma);
  var pw  = safeSig(powerB);
  var pb  = clamp01(MC_PBullNext);
  var ent = clamp01(MC_Entropy);

  plot("lambda",     lam, LINE, 0);
  plot("gamma",      gam, LINE, 0);
  plot("P_win",      pw,  LINE, 0);
  plot("PBullNext",  pb,  LINE, 0);
  plot("MC_Entropy", ent, LINE, 0);
}


  // Markov CSV log
  if(Bar % LOG_EVERY == 0){
    file_append(strf("Log\\%s_markov.csv",ALGO_NAME),
      strf("%i,%i,%.6f,%.6f,%i\n", Bar, MC_Cur, MC_PBullNext, MC_Entropy, MC_RowSum[MC_Cur]));
  }

  // ====== Entries ======
  if(Train){
    // Ensure samples for RETURNS training (hedged & 1-bar life set above)
    if(NumOpenLong  == 0) enterLong();
    if(NumOpenShort == 0) enterShort();
  } else {
    // Markov-gated live logic
    if( MC_PBullNext > PBULL_LONG_TH  && lambda >  0.7 ) enterLong();
    if( MC_PBullNext < PBULL_SHORT_TH && lambda < -0.7 ) enterShort();
  }
}

// Clean up memory
function cleanup()
{
  if(Root) freeTree(Root);
  MC_free();
  freeNet();
}

Last edited by TipmyPip; 09/04/25 18:18.