// ------------------- DTREE ensemble term ------------------
var dtreeTerm(int i, int* outTopEq, var* outTopW){
int j;
int tid_i = dt.safeTreeIndexFromEq((int)net.EqTreeId[i], dt.TreeN);
Node* ti = dt.treeAt(tid_i);
int di = ti->d; var ri=ti->r;
var predI = dt.predByTid(tid_i);
var alpha = (var)net.TAlpha[i];
var beta = (var)net.TBeta[i];
var sumw=0, acc=0, bestW=-1; int bestJ=-1;
for(j=0;j<net.N;j++){
if(j==i) continue;
int tid_j = dt.safeTreeIndexFromEq((int)net.EqTreeId[j], dt.TreeN);
Node* tj=dt.treeAt(tid_j);
int dj=tj->d; var rj=tj->r;
var predJ = dt.predByTid(tid_j);
var w = exp(-alpha*abs(di-dj)) * exp(-beta*abs(ri-rj));
var predBoost = 0.5 + 0.5*(predI*predJ);
var propBoost = 0.5 + 0.5*( (net.Prop[i] + net.Prop[j]) );
w *= predBoost * propBoost;
var pairAdv = scorePairSafe(i,j,0,0,0,0);
var pairBoost = 0.75 + 0.25*(0.5*(pairAdv+1.0));
w *= pairBoost;
sumw += w;
acc += w*net.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;
}
// ------------------- expression builder (optional) --------------------
void buildSymbolicExpr(int i, int n1, int n2){
if(!LOG_EXPR_TEXT) return;
if(!net.Sym) return;
string s = net.Sym[i];
s[0]=0;
string a1 = strf("(%.3f*x[%i] + %.3f*lam + %.3f*mean + %.5f*E + %.3f*P + %.3f*i + %.3f)",
(var)net.A1x[i], n1, (var)net.A1lam[i], (var)net.A1mean[i], (var)net.A1E[i], (var)net.A1P[i], (var)net.A1i[i], (var)net.A1c[i]);
string a2 = strf("(%.3f*x[%i] + %.3f*lam + %.3f*mean + %.5f*E + %.3f*P + %.3f*i + %.3f)",
(var)net.A2x[i], n2, (var)net.A2lam[i], (var)net.A2mean[i], (var)net.A2E[i], (var)net.A2P[i], (var)net.A2i[i], (var)net.A2c[i]);
Alpha12Logger::strlcat_safe(s, "x[i]_next = ", EXPR_MAXLEN);
Alpha12Logger::strlcat_safe(s, strf("%.3f*x[i] + ", (var)net.WSelf[i]), EXPR_MAXLEN);
if(net.Mode[i]==1){
Alpha12Logger::strlcat_safe(s, strf("%.3f*tanh%s + ", (var)net.WN1[i], a1), EXPR_MAXLEN);
Alpha12Logger::strlcat_safe(s, strf("%.3f*sin%s + ", (var)net.WN2[i], a2), EXPR_MAXLEN);
} else if(net.Mode[i]==2){
Alpha12Logger::strlcat_safe(s, strf("%.3f*cos%s + ", (var)net.WN1[i], a1), EXPR_MAXLEN);
Alpha12Logger::strlcat_safe(s, strf("%.3f*tanh%s + ", (var)net.WN2[i], a2), EXPR_MAXLEN);
} else {
Alpha12Logger::strlcat_safe(s, strf("%.3f*sin%s + ", (var)net.WN1[i], a1), EXPR_MAXLEN);
Alpha12Logger::strlcat_safe(s, strf("%.3f*cos%s + ", (var)net.WN2[i], a2), EXPR_MAXLEN);
}
Alpha12Logger::strlcat_safe(s, strf("%.3f*tanh(%.3f*mean + %.5f*E) + ",
(var)net.WGlob1[i], (var)net.G1mean[i], (var)net.G1E[i]), EXPR_MAXLEN);
Alpha12Logger::strlcat_safe(s, strf("%.3f*sin(%.3f*P + %.3f*lam) + ",
(var)net.WGlob2[i], (var)net.G2P[i], (var)net.G2lam[i]), EXPR_MAXLEN);
Alpha12Logger::strlcat_safe(s, strf("%.3f*(x[i]-x_prev[i]) + ", (var)net.WMom[i]), EXPR_MAXLEN);
Alpha12Logger::strlcat_safe(s, strf("Prop[i]=%.4f; ", (var)net.Prop[i]), EXPR_MAXLEN);
Alpha12Logger::strlcat_safe(s, strf("%.3f*DT(i) + ", (var)net.WTree[i]), EXPR_MAXLEN);
Alpha12Logger::strlcat_safe(s, strf("%.3f*DTREE(i)", (var)net.WAdv[i]), EXPR_MAXLEN);
}
void buildSymbolicExpr_range(int i0,int i1){
if(!LOG_EXPR_TEXT) return;
if(i0<0) i0=0; if(i1>net.N) i1=net.N;
int i;
for(i=i0;i<i1;i++){
int n1 = net.adjSafe(i,0);
int n2 = ifelse(net.D>=2, net.adjSafe(i,1), n1);
buildSymbolicExpr(i,n1,n2);
}
}
// ------------------- chunked rewire orchestrator ----------------------
int rewireEpochChunk(var lambda, var mean, var energy, var power, int batch){
if(net.N <= 0) return 0;
if(batch < REWIRE_MIN_BATCH) batch = REWIRE_MIN_BATCH;
if(RewirePos >= net.N) RewirePos = 0;
int i0 = RewirePos;
int i1 = i0 + batch; if(i1 > net.N) i1 = net.N;
CandNeigh = ifelse(MH.Entropy < 0.45, CAND_NEIGH+4, CAND_NEIGH);
rewireAdjacency_DTREE_range(i0,i1, lambda,mean,energy,power);
net.sanitizeAdjacency();
synthesizeEquation_range(i0,i1, lambda,mean,energy,power);
buildSymbolicExpr_range(i0,i1);
RewirePos = i1;
if(RewirePos >= net.N){
RewirePos = 0;
RewirePasses++;
return 1;
}
return 0;
}
void rewireEpoch(var lambda, var mean, var energy, var power){
int done=0;
while(!done){
done = rewireEpochChunk(lambda,mean,energy,power, REWIRE_BATCH_EQ_H1);
}
net.normalizeProportions();
{
int D = net.D, i, total = net.N*D;
unsigned int h = 2166136261u;
for(i=0;i<total;i++){
unsigned int x = (unsigned int)net.Adj[i];
h ^= x + 0x9e3779b9u + (h<<6) + (h>>2);
}
CtxID = (int)((h ^ ((unsigned int)Epoch<<8)) & 0x7fffffff);
}
}
// ------------------- coarse net projection -> gamma -------------------
var projectNet(){
int i;
var sum=0,sumsq=0,cross=0;
for(i=0;i<net.N;i++){
sum += net.State[i];
sumsq += net.State[i]*net.State[i];
if(i+1<net.N) cross += net.State[i]*net.State[i+1];
}
var mean = sum/net.N;
var corr = cross/(net.N-1);
return 0.6*tanh(mean + 0.001*sumsq) + 0.4*sin(corr);
}
// ------------------- heavy update chunk (OpenCL-batched) --------------
var nonlin1(int i, int n1, var lam, var mean, var E, var P){
var x = net.State[n1];
var arg = (var)net.A1x[i]*x + (var)net.A1lam[i]*lam + (var)net.A1mean[i]*mean + (var)net.A1E[i]*E + (var)net.A1P[i]*P + (var)net.A1i[i]*i + (var)net.A1c[i];
return arg;
}
var nonlin2(int i, int n2, var lam, var mean, var E, var P){
var x = net.State[n2];
var arg = (var)net.A2x[i]*x + (var)net.A2lam[i]*lam + (var)net.A2mean[i]*mean + (var)net.A2E[i]*E + (var)net.A2P[i]*P + (var)net.A2i[i]*i + (var)net.A2c[i];
return arg;
}
int heavyUpdateChunk(var lambda, var mean, var energy, var power, int batch){
if(net.N <= 0) return 0;
if(batch < UPDATE_MIN_BATCH) batch = UPDATE_MIN_BATCH;
if(UpdatePos >= net.N) UpdatePos = 0;
int i0 = UpdatePos;
int i1 = i0 + batch; if(i1 > net.N) i1 = net.N;
net.computeProjection();
if(OclReady) {
computeAdviceBatchRange(i0, i1, lambda, mean, energy, power);
} else {
resetAdvCacheForBar();
}
for(int i=i0;i<i1;i++){
int n1 = net.adjSafe(i,0);
int n2 = ifelse(net.D>=2, net.adjSafe(i,1), n1);
int topEq=-1; var topW=0;
var treeT = dtreeTerm(i, &topEq, &topW);
net.TreeTerm[i] = (fvar)treeT;
net.TopEq[i] = (i16)topEq;
net.TopW[i] = (fvar)topW;
var adv = adviseEq(i, lambda, mean, energy, power);
var a1 = nonlin1(i,n1,lambda,mean,energy,power);
var a2 = nonlin2(i,n2,lambda,mean,energy,power);
var t1,t2;
if(net.Mode[i]==1){ t1=tanh(a1); t2=sin(a2); }
else if(net.Mode[i]==2){ t1=cos(a1); t2=tanh(a2); }
else { t1=sin(a1); t2=cos(a2); }
var glob1 = tanh((var)net.G1mean[i]*mean + (var)net.G1E[i]*energy);
var glob2 = sin ((var)net.G2P[i]*power + (var)net.G2lam[i]*lambda);
var mom = (net.State[i] - net.Prev[i]);
var xnext =
(var)net.WSelf[i]*net.State[i]
+ (var)net.WN1[i]*t1
+ (var)net.WN2[i]*t2
+ (var)net.WGlob1[i]*glob1
+ (var)net.WGlob2[i]*glob2
+ (var)net.WMom[i]*mom
+ (var)net.WTree[i]*treeT
+ (var)net.WAdv[i]*adv;
xnext = clamp(xnext, -10., 10.);
net.Prev[i] = net.State[i];
net.State[i] = xnext;
net.StateSq[i] = xnext*xnext;
net.AdvPrev[i] = (fvar)adv;
if(!rt.LogsOff && (Bar % LOG_EVERY)==0 && (i < LOG_EQ_SAMPLE)){
int tid = dt.safeTreeIndexFromEq((int)net.EqTreeId[i], dt.TreeN);
Node* tnode = dt.treeAt(tid);
int nodeDepth = (tnode ? tnode->d : 0);
var rate = (var)net.TBeta[i];
var pred = dt.predByTid(tid);
string expr = 0;
if(LOG_EXPR_TEXT && net.Sym) expr = net.Sym[i];
log.appendEqMetaLine(Bar, Epoch, CtxID,
i, n1, n2, tid, nodeDepth, rate, pred, adv, net.Prop[i], (int)net.Mode[i],
(var)net.WAdv[i], (var)net.WTree[i], MH.PBullNext, MH.Entropy, (int)MH.Cur,
expr);
}
}
UpdatePos = i1;
if(UpdatePos >= net.N){
UpdatePos = 0;
UpdatePasses++;
return 1;
}
return 0;
}
// ------------------- hit-rate scorer ----------------------
void updateHitRates(){
if(is(INITRUN)) return;
if(Bar <= LookBack) return;
var r = net.Ret1;
var sgnR = sign(r);
for(int i=0;i<net.N;i++){
var a = (var)net.AdvPrev[i];
var sgnA = ifelse(a > 0.0001, 1, ifelse(a < -0.0001, -1, 0));
var hit = ifelse(sgnR == 0, 0.5, ifelse(sgnA == sgnR, 1.0, 0.0));
net.HitEW[i] = (fvar)((1.0 - 0.02)*(var)net.HitEW[i] + 0.02*hit);
net.HitN[i] += 1;
}
}
// ------------------- blend lambda/gamma & accuracy --------------------
var blendLambdaGamma(var lambda_raw, var gamma_raw){
var w = clamp(FB_W + 0.15*(0.5 - MH.Entropy), 0.4, 0.9);
var x = w*lambda_raw + (1.0 - w)*gamma_raw;
rt.acc_update(lambda_raw, gamma_raw);
return x;
}
// ------------------- rewire scheduler ----------------
void maybeRewireNow(var lambda, var mean, var energy, var power){
int mb = mem_mb_est();
if(mb >= UPDATE_MEM_HARD) return;
int batch = ifelse(is_H1_close(), REWIRE_BATCH_EQ_H1, REWIRE_BATCH_EQ_5M);
if(mb >= REWIRE_MEM_SOFT) batch = (batch>>1);
if(batch < REWIRE_MIN_BATCH) batch = REWIRE_MIN_BATCH;
int finished = rewireEpochChunk(lambda,mean,energy,power,batch);
if(finished && (RewirePasses % REWIRE_NORM_EVERY) == 0){
net.normalizeProportions();
log.writeEqHeaderOnce();
if((RewirePasses % META_EVERY) == 0){
int D = net.D, i, total = net.N*D;
unsigned int h = 2166136261u;
for(i=0;i<total;i++){
unsigned int x = (unsigned int)net.Adj[i];
h ^= x + 0x9e3779b9u + (h<<6) + (h>>2);
}
CtxID = (int)((h ^ ((unsigned int)Epoch<<8)) & 0x7fffffff);
}
}
}
// ------------------- heavy update scheduler ----------------
void runHeavyUpdates(var lambda, var mean, var energy, var power){
int mb = mem_mb_est();
if(mb >= UPDATE_MEM_HARD) return;
int batch = ifelse(is_H1_close(), UPDATE_BATCH_EQ_H1, UPDATE_BATCH_EQ_5M);
if(mb >= UPDATE_MEM_SOFT) batch = (batch>>1);
if(batch < UPDATE_MIN_BATCH) batch = UPDATE_MIN_BATCH;
heavyUpdateChunk(lambda,mean,energy,power,batch);
}
// ------------------- main engine step ---------------------
void alpha12_step(var ret1_now){
if(!ready) return;
updateAllMarkov();
if(Bar < LookBack){
net.computeProjection();
net.Ret1 = ret1_now;
var h=0;
for(int i=0;i<net.N;i++) h += (var)net.HitEW[i];
if(net.N > 0) h /= (var)net.N; else h=0.5;
var target = MC_ACT + 0.15*(0.55 - h) + 0.10*(MH.Entropy - 0.5);
target = clamp(target, 0.20, 0.50);
MC_ACT_dyn = 0.95*MC_ACT_dyn + 0.05*target;
return;
}
net.computeProjection();
int Keff = net.keffClamped();
var e=0, pwr=0;
for(int k=0;k<Keff;k++){ var z=(var)net.Z[k]; e+=z; pwr+=z*z; }
var mean=0, power=0;
if(Keff > 0){ mean = e/(var)Keff; power = pwr/(var)Keff; }
var energy = pwr;
var lambda = 0.7*tanh(mean) + 0.3*tanh(0.05*power);
maybeRewireNow(lambda,mean,energy,power);
runHeavyUpdates(lambda,mean,energy,power);
var gamma = projectNet();
var x = blendLambdaGamma(lambda,gamma);
(void)x;
dt.updateEquationCycle(net.Prop, net.N);
net.Ret1 = ret1_now;
updateHitRates();
int beforeDepth = rt.RT_TreeMaxDepth;
rt.depth_manager_runtime(dt);
if(rt.RT_TreeMaxDepth != beforeDepth){
reindexTreeAndMap();
}
{
var h=0;
for(int i=0;i<net.N;i++) h += (var)net.HitEW[i];
if(net.N > 0) h /= (var)net.N; else h=0.5;
var target = MC_ACT + 0.15*(0.55 - h) + 0.10*(MH.Entropy - 0.5);
target = clamp(target, 0.20, 0.50);
MC_ACT_dyn = 0.9*MC_ACT_dyn + 0.1*target;
}
}
// ------------------- realized 1-bar return ----------------
var realizedRet1(){
vars C = series(priceClose(0));
if(Bar <= LookBack) return 0;
return C[0] - C[1];
}
// ------------------- trading signal -----------------------
var tradeSignal(){
if(!ready) return 0;
if(!net.RP || !net.Z || !net.StateSq) return 0;
net.computeProjection();
int Keff = net.keffClamped();
if(Keff <= 0) return 0;
var e=0, pwr=0;
for(int k=0;k<Keff;k++){ var z=(var)net.Z[k]; e+=z; pwr+=z*z; }
var mean=0, power=0;
if(Keff > 0){ mean = e/(var)Keff; power = pwr/(var)Keff; }
var lambda = 0.7*tanh(mean) + 0.3*tanh(0.05*power);
var gamma = projectNet();
var x = blendLambdaGamma(lambda,gamma);
LastSig = x;
var gLong=0, gShort=0;
if(MH.PBullNext >= PBULL_LONG_TH) gLong = 1.0;
if(MH.PBullNext <= PBULL_SHORT_TH) gShort= 1.0;
var s=0;
if(x > 0) s = x*gLong;
else s = x*gShort;
var conf = 1.0 - 0.5*(MR.Entropy);
s *= conf;
return clamp(s,-1.,1.);
}
// ------------------- position sizing & orders -------------
var posSizeFromSignal(var s){
var base = 1;
var scale = 2.0*abs(s);
return base * (0.5 + 0.5*scale);
}
void placeOrders(var s){
if(s > 0){
if(NumOpenShort) exitShort();
if(!NumOpenLong){
Lots = posSizeFromSignal(s);
enterLong();
}
} else if(s < 0){
if(NumOpenLong) exitLong();
if(!NumOpenShort){
Lots = posSizeFromSignal(s);
enterShort();
}
}
}
void plotSafe(string name, var v){
if(ENABLE_PLOTS && !rt.ChartsOff) plot(name, v, NEW|LINE, 0);
}
void onBar(){
var r1 = realizedRet1();
alpha12_step(r1);
var s = tradeSignal();
placeOrders(s);
plotSafe("PBull(1H)", 100*(MH.PBullNext-0.5));
plotSafe("PBull(5M)", 100*(ML.PBullNext-0.5));
plotSafe("PBull(Rel)", 100*(MR.PBullNext-0.5));
plotSafe("Entropy(1H)", 100*(MH.Entropy));
plotSafe("Sig", 100*LastSig);
}
// ----------------------- init/cleanup ----------------------
void init() {
if(ready) return;
BarPeriod = BAR_PERIOD;
LookBack = max(300, NWIN);
set(PLOTNOW);
asset(ASSET_SYMBOL);
net.Keff = KPROJ;
if(net.Keff < 1) net.Keff = 1;
if(net.Keff > net.K) net.Keff = net.K;
net.allocate();
MH.alloc(); ML.alloc(); MR.alloc();
MH.Alpha = MC_Alpha; ML.Alpha = MC_Alpha; MR.Alpha = MC_Alpha;
dt.allocDepthLUT();
dt.DTreeExp = 0;
dt.Root = dt.createNode(MAX_DEPTH);
rt.RT_TreeMaxDepth = MAX_DEPTH;
dt.refreshDepthW();
reindexTreeAndMap();
net.randomizeRP();
net.computeProjection();
rewireEpoch(0,0,0,0);
log.writeEqHeaderOnce();
RewirePos=0; RewirePasses=0;
UpdatePos=0; UpdatePasses=0;
seedBar = -1;
memset(haveSeed,0,sizeof(haveSeed));
// ---- OpenCL advisor init ----
OclReady = 0;
if(ocl.init(ADV_EQ_NF, NET_EQNS)) {
OclReady = 1;
}
AdvCacheBar = -999999;
memset(AdvHave,0,sizeof(AdvHave));
memset(AdvCache,0,sizeof(AdvCache));
ready = 1;
printf("\n[Alpha12] init done: N=%i D=%i K=%i (Keff=%i) Depth=%i est=%i MB OpenCL=%i",
net.N, net.D, net.K, net.Keff, rt.RT_TreeMaxDepth, mem_mb_est(), OclReady);
}
void cleanup() {
if(!ready) return;
if(OclReady) {
ocl.shutdown();
OclReady = 0;
}
MH.freeMem(); ML.freeMem(); MR.freeMem();
dt.freeAll();
pool.freeAll();
net.freeAll();
ready = 0;
}
};
// ======================================================================
// ========================= Zorro DLL entry (bridge) ====================
DLLFUNC void run()
{
if(is(INITRUN)) {
if(!gAlpha12) gAlpha12 = new Alpha12Strategy();
gAlpha12->init();
}
if(!gAlpha12 || !gAlpha12->ready)
return;
if(is(LOOKBACK) || Bar < LookBack) {
gAlpha12->updateAllMarkov();
gAlpha12->net.computeProjection();
return;
}
gAlpha12->onBar();
if(is(EXITRUN)) {
gAlpha12->cleanup();
delete gAlpha12;
gAlpha12 = nullptr;
}
}