Gamestudio Links
Zorro Links
Newest Posts
ZorroGPT
by TipmyPip. 01/22/26 12:25
MRC.c and WFO
by 11honza11. 01/22/26 10:33
Buy A8 Pro Version
by Spirit. 01/21/26 21:37
Bar missing bug?
by jcl. 01/19/26 10:47
400 free seamless texture pack downl. here !
by NeoDumont. 01/18/26 19:09
AUM Magazine
Latest Screens
Rocker`s Revenge
Stug 3 Stormartillery
Iljuschin 2
Galactic Strike X
Who's Online Now
3 registered members (TipmyPip, 2 invisible), 8,927 guests, and 3 spiders.
Key: Admin, Global Mod, Mod
Newest Members
Castromangos, Quantum, stephensdeborah, promfast, joe_kane
19193 Registered Users
Previous Thread
Next Thread
Print Thread
Rate Thread
Page 12 of 12 1 2 10 11 12
Empirical Analysis of Asset Prices [Re: TipmyPip] #488964
11/08/25 22:28
11/08/25 22:28
Joined: Sep 2017
Posts: 181
TipmyPip Online OP
Member
TipmyPip  Online OP
Member

Joined: Sep 2017
Posts: 181
What are “Shiller equations”?

Present-value model & variance bounds: Price equals the discounted stream of expected future payouts. Under rational expectations, the variance of price can’t exceed the variance of the discounted-cash-flow process; Shiller showed stock prices are too volatile relative to this bound (“Do Stock Prices Move Too Much…”, AER 1981).
American Economic Association

Campbell–Shiller log-linear identity: A log-linearization of the present-value model links the log dividend-price ratio to expected future returns and dividend growth, yielding testable decompositions widely used in asset-pricing.
Stern School of Business


Key PDFs (authoritative):

Shiller (1981) AER — “Do Stock Prices Move Too Much to be Justified by Subsequent Changes in Dividends?” (classic variance-bounds test).
American Economic Association

Campbell & Shiller (1988, RFS/NBER) — “The Dividend-Price Ratio and Expectations of Future Dividends and Discount Factors” (log-linear present-value relation).
Stern School of Business


Nobel Prize 2013 press release (PDF) — award to Fama, Hansen, Shiller “for their empirical analysis of asset prices.”
NobelPrize.org


Shiller’s Nobel Prize lecture (PDF): “Speculative Asset Prices.”
NobelPrize.org

Nobel “Popular Science” background (PDF): “Trendspotting in asset markets.”
NobelPrize.org


Code
// ============================================================================
// Shiller_EURUSD.c  —  Zorro / lite-C demonstration script (EUR/USD)
// ============================================================================
// GOAL
// -----
// This script illustrates two classic ideas often discussed in the
// 'variance bounds' / 'dividend–price ratio' (dp) literature:
//
//   Part A) An *illustrative* check of "excess volatility":
//           compare the variance of price P_t to a discounted-sum proxy P*_t
//           constructed from a toy 'dividend' series D_t (here: carry proxy).
//
//   Part B) A very simple *return predictability* example using the
//           dividend-price ratio dp_t := log(D_t / P_t) to predict future
//           K-day returns via a rolling univariate OLS slope.
//
// NOTES (Zorro / lite-C specifics)
// --------------------------------
// • This is a research demo; it trades with a minimal rule only to show how to
//   translate a scalar signal into actions. It is *not* a strategy.
// • Positive series index in Zorro points to the PAST. Example: X[1] is
//   the previous bar, X[K] is K bars ago; X[0] is the current bar.
// • `vars` are rolling series returned by `series(...)`; `var` is a scalar.
// • `asset("EUR/USD")` selects the EUR/USD symbol defined by your asset list.
// • `Lots` is set to 1 purely for a visible action in Part B.
//
// SAFETY / ROBUSTNESS
// -------------------
// • We clamp denominators with a small epsilon to avoid log(0) or division by 0.
// • Window sizes and horizons are explicitly checked against LookBack and Bar.
//
// VERSION
// -------
// Tested with Zorro 2.x / lite-C syntax.
// ============================================================================

function run()
{
    // ------------------------------------------------------------------------
    // SESSION / DATA SETTINGS
    // ------------------------------------------------------------------------
    BarPeriod = 1440;      // 1440 minutes = 1 day bars
    StartDate = 2010;      // start year (use your data span)
    LookBack  = 600;       // bars held in rolling series (must cover max windows)
    asset("EUR/USD");
    set(PLOTNOW);          // auto-plot series as they are produced

    // ------------------------------------------------------------------------
    // PRICE SERIES
    // ------------------------------------------------------------------------
    // P_t: close price; R1: 1-bar (1-day) log return (not used later, kept for ref)
    vars P  = series(priceClose());           // P[0]=today, P[1]=yesterday, ...
    vars R1 = series(log(P[0]/P[1]));         // ln(P_t / P_{t-1})

    // ------------------------------------------------------------------------
    // "DIVIDEND" PROXY D_t  (here: a constant carry series for demonstration)
    // ------------------------------------------------------------------------
    // In FX, a carry-like proxy could be the interest rate differential.
    // Here we just set a constant daily carry to mimic ~1.5% per annum.
    var  eps        = 1e-12;                  // small epsilon for safe divisions
    var  carryDaily = 0.015/252.;             // ? 1.5% p.a. / 252 trading days
    vars D          = series(carryDaily);     // D_t aligned with bars

    // =========================================================================
    // PART A: "Ex post" discounted-sum proxy P*_t for an excess-volatility check
    // =========================================================================
    // Construct a simple discounted sum of past D_t as a toy P*_t proxy:
    //     P*_t ? ?_{k=1..Kmax} D_{t-k} / (1+r_d)^k
    // This is ONLY an illustration, not a proper present-value model.
    int   Kmax = 126;                          // look-back horizon (~6 months)
    var   r_d  = 0.0001;                       // daily discount ? 0.01% (~2.5% p.a.)
    vars  Px   = series(0);                    // rolling proxy P*_t

    if (Bar > LookBack)
    {
        // Build discounted sum from *past* values of D (D[1]..D[Kmax])
        var sumDisc = 0;
        var disc    = 1;
        int k;
        for (k=1; k<=Kmax; k++)
        {
            disc   /= (1 + r_d);               // (1+r)^(-k)
            var Dp  = D[k];                    // D_{t-k}
            sumDisc += disc * Dp;
        }
        Px[0] = sumDisc;                       // write current P*_t proxy

        // Compare rolling variances of P and P* over a window W
        int W = 500;
        if (Bar > LookBack + Kmax + W)
        {
            // Means
            var meanP = 0, meanPx = 0;
            int i;
            for (i=0; i<W; i++) { meanP += P[i]; meanPx += Px[i]; }
            meanP  /= (var)W;
            meanPx /= (var)W;

            // Sample variances
            var varP = 0, varPx = 0;
            for (i=0; i<W; i++) {
                var a = P[i]-meanP;
                var b = Px[i]-meanPx;
                varP  += a*a;
                varPx += b*b;
            }
            varP  /= (var)(W-1);
            varPx /= (var)(W-1);

            // Plots for visual inspection
            plot("Var(P)",  varP,  NEW, 0);
            plot("Var(P*)", varPx, 0,   0);

            // Console line every ~50 bars
            if (Bar%50==0)
                printf("\n[EXCESS VOL] W=%d Var(P)=%.6g Var(P*)=%.6g ratio=%.3f",
                       W, varP, varPx, varP/(varPx+eps));
        }
    }

    // =========================================================================
    // PART B: Return predictability via the dividend-price ratio, dp_t
    // =========================================================================
    // We compute:
    //   dp_t := log(D_t / P_t)
    // and regress *past* K-day realized returns on dp over a rolling window Wreg
    // to estimate a slope 'beta'. A positive beta implies higher dp predicts
    // higher future returns (in this toy setup).
    //
    // Then we convert the instantaneous dp z-score into a small long/short
    // trade signal, clipped and scaled to the range [-0.5, +0.5] (Lev).
    int   K   = 20;                                            // horizon (~1 month)
    vars  DP  = series(log(max(eps, D[0]) / max(eps, P[0])));  // dp_t series
    vars  RK  = series(log(P[0]/P[K]));                        // realized K-day return

    int   Wreg = 500;                                          // regression window
    if (Bar > LookBack + K + Wreg)
    {
        // ----------------------------
        // Rolling univariate OLS slope
        // ----------------------------
        var sumX=0, sumY=0, sumXX=0, sumXY=0;
        int i;
        for (i=0;i<Wreg;i++){
            var x = DP[i];     // predictor
            var y = RK[i];     // response (past K-day return)
            sumX  += x;
            sumY  += y;
            sumXX += x*x;
            sumXY += x*y;
        }
        var meanX = sumX/Wreg;
        var meanY = sumY/Wreg;
        var denom = sumXX - Wreg*meanX*meanX;

        var beta = 0;                                         // OLS slope
        if (denom != 0)
            beta = (sumXY - Wreg*meanX*meanY)/denom;

        plot("beta(dp->Kret)", beta, NEW, 0);

        // ----------------------------
        // z-score of current dp_t
        // ----------------------------
        var meanDP=0, varDP=0;
        for (i=0;i<Wreg;i++) meanDP += DP[i];
        meanDP/=Wreg;
        for (i=0;i<Wreg;i++){ var d=DP[i]-meanDP; varDP += d*d; }
        varDP /= (Wreg-1);
        var sDP  = sqrt(max(eps,varDP));
        var zDP  = (DP[0]-meanDP)/sDP;

        // Clip z to avoid huge outliers
        var zClip = zDP;
        if (zClip >  2) zClip =  2;
        if (zClip < -2) zClip = -2;

        // Direction follows beta sign
        var sig = 0;
        if (beta > 0)      sig = zClip;
        else if (beta < 0) sig = -zClip;

        // ----------------------------
        // POSITION TRANSLATION
        // ----------------------------
        // Map raw signal in [-2,+2] to leverage-like knob in [-1,+1],
        // then cap at ±0.5 to keep actions small in the demo.
        var Target = sig;          // raw -2..+2
        var MaxLev = 0.5;          // clamp bound
        var Lev    = Target/2.0;   // scale to -1..+1 then cap
        if (Lev >  MaxLev) Lev =  MaxLev;
        if (Lev < -MaxLev) Lev = -MaxLev;

        // Minimal action rule:
        // if Lev is meaningfully positive => long; if negative => short; else flat.
        // We keep Lots=1 for visibility; no money management here.
        if (Lev > 0.05) { exitShort(); enterLong();  Lots = 1; }
        else if (Lev < -0.05) { exitLong(); enterShort(); Lots = 1; }
        else { exitLong(); exitShort(); }

        // Plots for monitoring
        plot("z(dp)", zDP, 0, 0);
        plot("lev",  Lev,  0, 0);
    }

    // End of run() — Zorro handles bar stepping automatically.
}

Attached Files
Shiller_EURUSD.zip (53 downloads)
Empirical Analysis of Asset Prices (with NN) [Re: TipmyPip] #488965
11/09/25 08:39
11/09/25 08:39
Joined: Sep 2017
Posts: 181
TipmyPip Online OP
Member
TipmyPip  Online OP
Member

Joined: Sep 2017
Posts: 181
the strategy encodes the Campbell–Shiller insight that high dividend/“carry” yields relative to price predict higher future returns, wraps that valuation in a z-scored
????????????, and lets a linear neural unit blend it with momentum/volatility states to produce directional edge; trades are taken when the learned edge clears a small threshold.

Code
// ============================================================================
// Shiller NN EUR/USD — ML trading demo (Zorro / lite-C)
//
// • Learner: PERCEPTRON (+BALANCED) on a compact 8-feature vector.
// • Trigger: edge = predL - predS with a simple RSI + momentum fallback.
// • Plots: (name, value, color, style); panels anchored correctly.
// ============================================================================

#include <default.c>

// ===== Configuration =====
#define LOOKBACK   200     // Bars required before running the model/logic
#define BarMins    1440    // Daily bars
#define LotsFixed  1       // Position size per entry
#define EdgeMin    0.05    // ML edge threshold (predL - predS) to trigger a trade

// ===== Safe helpers =====
var safe_div(var a, var b)
{
  if (invalid(a) || invalid(b) || b == 0) return 0;
  return a/b;
}

var safe_logratio(var a, var b)
{
  if (invalid(a) || invalid(b) || b == 0) return 0;
  var r = a/b;
  if (invalid(r) || r <= 0) return 0;
  return log(r);
}

// NOTE: plot(name, value, color, style)
// We'll pass color first, then style flags (e.g., LINE, NEW, MAIN, etc.)
void plot_safe(string name, var v, int color, int style)
{
  if (!invalid(v) && v > -1e-12 && v < 1e12)
    plot(name, v, color, style);
}

// ===== Main strategy =====
function run()
{
  // Session (file-free; no RULES ? no rule files created/loaded)
  StartDate = 2010;
  EndDate   = 2025;
  BarPeriod = BarMins;
  LookBack  = LOOKBACK;
  Capital   = 10000;
  set(PARAMETERS|PLOTNOW);
  Hedge = 0;
  asset("EUR/USD");

  // Base series
  vars PC = series(priceClose());  // Close series for returns/momentum
  vars PX = series(price());       // Price series for RSI

  // Derived series (allocated once, updated every bar)
  static vars R1;     if (!R1)    R1    = series(0);  // 1-bar log return
  static vars MOM5;   if (!MOM5)  MOM5  = series(0);  // 5-bar momentum
  static vars MOM20;  if (!MOM20) MOM20 = series(0);  // 20-bar momentum
  static vars DP;     if (!DP)    DP    = series(0);  // dp proxy = log(D/P)

  if (Bar > 0)  R1[0]    = safe_logratio(PC[0], PC[1]);   else R1[0]    = 0;
  if (Bar > 5)  MOM5[0]  = safe_logratio(PC[0], PC[5]);   else MOM5[0]  = 0;
  if (Bar > 20) MOM20[0] = safe_logratio(PC[0], PC[20]);  else MOM20[0] = 0;

  // Constant carry vs price ? dp_t = log(D_t / P_t) (simple demonstration proxy)
  var carryDaily = 0.015/252.;  // ~1.5% p.a.
  if (Bar > 0) DP[0] = safe_logratio(carryDaily, PC[0]); else DP[0] = 0;

  // Indicators with warmup guards
  var vola  = 0;  if (Bar >= 21) vola  = StdDev(R1, 20);
  var atr20 = 0;  if (Bar >= 21) atr20 = ATR(20);
  var rsi14 = 50; if (Bar >= 15) rsi14 = RSI(PX, 14);

  // dp z-score (window Wz)
  var zDP = 0; int Wz = 500;
  if (Bar >= Wz) {
    int i; var mean = 0, s2 = 0;
    for (i = 0; i < Wz; i++) mean += DP[i];
    mean /= (var)Wz;
    for (i = 0; i < Wz; i++) { var d = DP[i] - mean; s2 += d*d; }
    var sd = sqrt(max(1e-12, s2/(Wz - 1)));
    if (sd > 0) {
      zDP = (DP[0] - mean) / sd;
      if (zDP >  10) zDP =  10;
      if (zDP < -10) zDP = -10;
    }
  }

  if (Bar < LOOKBACK) {
    // Anchor price panel early so the chart opens immediately
    plot_safe("Close", priceClose(), 0, MAIN|LINE);
    return;
  }

  // Feature vector (?20)
  var F[8];
  F[0] = zDP;
  F[1] = MOM5[0];
  F[2] = MOM20[0];
  F[3] = vola;
  F[4] = rsi14/100.;
  F[5] = safe_div(atr20, PC[0]);
  F[6] = R1[0];
  F[7] = safe_logratio(PC[0], PC[10]);

  // Built-in ML (file-free: no RULES)
  var predL = adviseLong (PERCEPTRON + BALANCED, 0, F, 8);
  var predS = adviseShort(PERCEPTRON + BALANCED, 0, F, 8);

  // Trading logic: edge trigger with simple fallback
  var edge = predL - predS;
  Lots = LotsFixed;

  int didTrade = 0;
  if (!invalid(edge) && edge > EdgeMin) {
    exitShort(); enterLong();  didTrade = 1;
  } else if (!invalid(edge) && edge < -EdgeMin) {
    exitLong();  enterShort(); didTrade = 1;
  }

  if (!didTrade) {
    if (rsi14 > 55 && MOM5[0] > 0) { exitShort(); enterLong();  didTrade = 1; }
    else if (rsi14 < 45 && MOM5[0] < 0) { exitLong(); enterShort(); didTrade = 1; }
    else { exitLong(); exitShort(); }
  }

  // ===== Plots (color, style) =====
  // Price on the main chart
  plot_safe("Close", priceClose(), 0, MAIN|LINE);

  // Open a NEW indicator panel with 'edge', then add other lines to the same panel
  plot_safe("edge",  edge,  0, NEW|LINE);   // NEW opens the panel
  plot_safe("predL", predL, 0, LINE);
  plot_safe("predS", predS, 0, LINE);
  plot_safe("RSI",   rsi14, 0, LINE);
  plot_safe("z(dp)", zDP,   0, LINE);
}



A walkford version :

Code
// ============================================================================
// BLA03x10_WFO_train_test.c
// EUR/USD — Single-script ML trading with explicit Train/Test separation.
// Zorro / lite-C
//
// • Train run (click “Train”): writes per-cycle RULE files (no TESTNOW).
// • Test/Trade run (click “Test” or “Trade”): loads the RULE files created in Train.
// • Learner: PERCEPTRON + BALANCED 
// • WFO supported via NumWFOCycles + DataHorizon (same in Train & Test).
// • Consistent asset() + algo() + advise* signature in both phases.
// • No ternary operator; guarded indicators; compact 8-feature vector.
// ============================================================================

#include <default.c>

// ===== Switches / Knobs =====
#define USE_WFO         1        // 0 = single IS block; 1 = Walk-Forward (IS/OOS cycles)
#define WFO_CYCLES      6        // number of WFO cycles (Train & Test must match)
#define WFO_OOS_BARS    252      // OOS length per cycle in bars (daily ? 1y)

#define LOOKBACK        200      // warmup bars before any model/logic
#define BarMins         1440     // 1D bars
#define LotsFixed       1        // fixed position size
#define EdgeMin         0.05     // edge = predL - predS threshold

// ===== Safe helpers =====
var safe_div(var a,var b){ if(invalid(a)||invalid(b)||b==0) return 0; return a/b; }
var safe_logratio(var a,var b){
  if(invalid(a)||invalid(b)||b==0) return 0;
  var r=a/b; if(invalid(r)||r<=0) return 0; return log(r);
}
// plot(name, value, color, style)
void plot_safe(string n, var v, int c, int s){ if(!invalid(v)&&v>-1e12&&v<1e12) plot(n,v,c,s); }

// ===== Main =====
function run()
{
  // -------- Session (identical in Train and Test except RULES/Hedge flags) --------
  StartDate = 2010;
  EndDate   = 2025;
  BarPeriod = BarMins;
  LookBack  = LOOKBACK;
  Capital   = 10000;

  if(USE_WFO){
    NumWFOCycles = WFO_CYCLES;
    DataHorizon  = WFO_OOS_BARS;         // OOS size per cycle
  } else {
    NumWFOCycles = 1;
    DataHorizon  = 0;
  }

  set(PARAMETERS|PLOTNOW);               // common flags

  // Explicit Train/Test separation (no TESTNOW auto phase switching)
  if(Train){
    set(RULES);                          // write RULE files during Train only
    Hedge = 2;                           // generate both L/S samples while training
  } else {
    Hedge = 0;                           // Test/Trade loads RULE files, no writing
  }

  asset("EUR/USD");
  algo("dp");                            // part of RULE key: <Asset>:<Algo>:<L|S>

  // -------- Base series --------
  vars PC = series(priceClose());        // close for returns/momentum
  vars PX = series(price());             // price for RSI

  // -------- Derived series (allocated once, updated every bar) --------
  static vars R1;     if(!R1)    R1    = series(0);  // 1-bar log return
  static vars MOM5;   if(!MOM5)  MOM5  = series(0);  // 5-bar log momentum
  static vars MOM20;  if(!MOM20) MOM20 = series(0);  // 20-bar log momentum
  static vars DP;     if(!DP)    DP    = series(0);  // dp proxy = log(D/P)

  if(Bar > 0)  R1[0]    = safe_logratio(PC[0],PC[1]);  else R1[0]    = 0;
  if(Bar > 5)  MOM5[0]  = safe_logratio(PC[0],PC[5]);  else MOM5[0]  = 0;
  if(Bar > 20) MOM20[0] = safe_logratio(PC[0],PC[20]); else MOM20[0] = 0;

  var carryDaily = 0.015/252.;
  if(Bar > 0) DP[0] = safe_logratio(carryDaily, PC[0]); else DP[0] = 0;

  // -------- Indicators with guards --------
  var vola  = 0;  if(Bar >= 21) vola  = StdDev(R1,20);
  var atr20 = 0;  if(Bar >= 21) atr20 = ATR(20);
  var rsi14 = 50; if(Bar >= 15) rsi14 = RSI(PX,14);

  // -------- dp z-score (window Wz) --------
  var zDP = 0; int Wz = 500;
  if(Bar >= Wz){
    int i; var mean=0, s2=0;
    for(i=0;i<Wz;i++) mean += DP[i];
    mean /= (var)Wz;
    for(i=0;i<Wz;i++){ var d = DP[i]-mean; s2 += d*d; }
    var sd = sqrt(max(1e-12, s2/(Wz-1)));
    if(sd > 0){
      zDP = (DP[0]-mean)/sd;
      if(zDP > 10)  zDP = 10;
      if(zDP < -10) zDP = -10;
    }
  }

  // Anchor main panel early
  if(Bar < LOOKBACK){
    plot_safe("Close", priceClose(), BLACK, MAIN|LINE);
    return;
  }

  // -------- Feature vector (? 20) --------
  var F[8];
  F[0] = zDP;
  F[1] = MOM5[0];
  F[2] = MOM20[0];
  F[3] = vola;
  F[4] = rsi14/100.;
  F[5] = safe_div(atr20, PC[0]);
  F[6] = R1[0];
  F[7] = safe_logratio(PC[0], PC[10]);

  // -------- Built-in ML calls (IDENTICAL in Train & Test) --------
  // Important: same method flags, same slot number, same feature length & order,
  // same asset() and algo() ? ensures matching rule keys and file names.
  var predL = adviseLong (PERCEPTRON + BALANCED, 0, F, 8);
  var predS = adviseShort(PERCEPTRON + BALANCED, 0, F, 8);

  // -------- Execution logic (common) --------
  var edge = predL - predS;
  Lots = LotsFixed;

  int didTrade = 0;
  if(!invalid(edge) && edge > EdgeMin){ exitShort(); enterLong();  didTrade = 1; }
  else if(!invalid(edge) && edge < -EdgeMin){ exitLong(); enterShort(); didTrade = 1; }

  if(!didTrade){
    if(rsi14 > 55 && MOM5[0] > 0) { exitShort(); enterLong();  didTrade = 1; }
    else if(rsi14 < 45 && MOM5[0] < 0) { exitLong(); enterShort(); didTrade = 1; }
    else { exitLong(); exitShort(); }
  }

  // -------- Plots --------
  plot_safe("Close", priceClose(), BLACK, MAIN|LINE);
  plot_safe("edge",  edge,  GREEN, NEW|LINE);
  plot_safe("predL", predL, BLUE,  LINE);
  plot_safe("predS", predS, RED,   LINE);
  plot_safe("RSI",   rsi14, 0x404040, LINE);
  plot_safe("z(dp)", zDP,   0x800080, LINE);
}

Attached Files
MShillerNN_EURUSD.zip (57 downloads)
Last edited by TipmyPip; 11/09/25 11:26.
Re: Empirical Analysis of Asset Prices (with NN) [Re: TipmyPip] #488966
11/10/25 11:04
11/10/25 11:04
Joined: Sep 2017
Posts: 181
TipmyPip Online OP
Member
TipmyPip  Online OP
Member

Joined: Sep 2017
Posts: 181
I have a question for all my Dear fellow programmers, If you had a book of one single strategy, 500 pages, explaining with detailed descriptions how to develop and come about complex strategies, how much would you be willing to pay for a copy of the book?

Thank you for your attention, and thoughtful consideration?

SAR MOMENTUM BOT [Re: TipmyPip] #488982
11/19/25 10:10
11/19/25 10:10
Joined: Sep 2017
Posts: 181
TipmyPip Online OP
Member
TipmyPip  Online OP
Member

Joined: Sep 2017
Posts: 181
This script is a Zorro trading strategy that trades EUR/USD on 5-minute bars using the Parabolic SAR for direction and an optional momentum filter:


It optimizes five core parameters: SAR_STEP (SAR sensitivity), DRAW_BEFORE_SL_POINTS (how far price must move against you before a delayed stop is placed),
STOP_POINTS (fixed stop-loss in pips), TAKEPROFIT_POINTS (fixed take-profit in pips),MAX_HOLD_BARS (maximum number of bars a trade may stay open).

On each bar it:

Computes SAR and recent price movement. Generates long/short signals based on whether SAR is below or above price, refined by momentum and basic filters (spread, session, news stubs).
Closes trades either when an opposite SAR signal appears or when they exceed MAX_HOLD_BARS.
Opens 1-lot market orders (no position sizing logic yet) with the optimized SL/TP and uses SarTMF to apply a delayed stop-loss once the trade has moved against you by a configurable amount.
It also logs detailed per-bar info to GoldSarDebug.csv for debugging and analysis.

With a little creative mind this one can improve alot.


Code
// ======================================================
//  SAR MOMENTUM BOT
//  SAR direction entries, optional momentum filter,
//  + optimizable SAR step / delayed SL / StopLoss / TakeProfit / Max holding time
// ======================================================

#include <default.c>
#include <stdio.h>   // for file-based debug logging

//------------------------------------------------------//
//  USER PARAMETERS (defaults – some are overwritten by optimize())
//------------------------------------------------------//

// Bar timeframe for SAR etc. (minutes)
int      TRADE_TIMEFRAME      = 5;       // M5

// Parabolic SAR params (Zorro SAR(Step,Min,Max))
var      SAR_STEP             = 0.02;
var      SAR_MAX              = 0.20;
var      SAR_MIN              = 0.02;    // usually same as step

// Distance from price for pending order (in pips)
int      SAR_BUFFER_POINTS    = 25;

// Trading session
int      USE_GMT_TIME         = 1;       // (unused – hour(0) is used)
int      SESSION_START_HOUR   = 7;       // 0..23
int      SESSION_END_HOUR     = 21;      // 0..23

// News filter (stub – always off unless implemented)
int      USE_NEWS_FILTER      = 0;

// Lot size modes
#define LOT_FIXED_LOT         0
#define LOT_BALANCE_PERCENT   1
#define LOT_EQUITY_PERCENT    2
#define LOT_FIXED_RISK_MONEY  3

int      LotMode            = LOT_BALANCE_PERCENT;
var      FIXED_LOT_SIZE     = 0.10;
var      RISK_PERCENT       = 0.5;     // for BALANCE/EQUITY
var      FIXED_RISK_MONEY   = 50.0;    // account currency

// Momentum filter window (seconds)
int      ACTIVATE_WINDOW_SEC  = 900;   // default ~15 minutes
int      ACTIVATE_MOVE_POINTS = 10;    // min move in window (pips)

// Pending expiry / staleness windows (seconds)
int      PENDING_EXPIRE_SEC   = 30;   // hard life of pending (unused with market)
int      STALE_WINDOW_SEC     = 15;   // after this, require min move
int      STALE_MOVE_POINTS    = 30;   // else cancel

// Delayed stop-loss (used only by TMF when Stop==0)
int      DRAW_BEFORE_SL_POINTS  = 60;  // move against trade before SL is drawn
int      EXTRA_SL_BUFFER_POINTS = 25;  // SL extra buffer beyond current price

// Concurrency & spread
int      MAX_CONCURRENT_ORDERS  = 1;   // informational only
var      MAX_SPREAD_POINTS      = 20;  // in pips

// Explicit exits (in pips, will be converted to price units by *PIP)
// THESE THREE + SAR_STEP + DRAW_BEFORE_SL_POINTS ARE OPTIMIZED
int      STOP_POINTS            = 40;   // fixed SL in pips
int      TAKEPROFIT_POINTS      = 60;   // fixed TP in pips
int      MAX_HOLD_BARS          = 72;   // max bars a trade can stay open

//------------------------------------------------------//
//  INTERNAL STATE
//------------------------------------------------------//

#define HISTORY_SIZE 200

var   PriceHistory[HISTORY_SIZE];   // tick Bid approximation
var   TimeHistory[HISTORY_SIZE];    // windows DATE stamps
var   SpreadHistory[HISTORY_SIZE];  // spread in pips

// Last SAR value (updated per bar in run())
var   SarValue = 0;

// Optional status text for UI / debugging
string RestrictionReason = "";

// small debug switch (set to 1 if you want printf logs)
int    DEBUG_LOG = 0;

// debug counter: how many times entry conditions were true
int    EntrySignalCount = 0;

// helper switches for backtest
int    RELAX_FILTERS_FOR_BACKTEST      = 1;  // 1 = no spread/session/momentum/news blocking
int    USE_MARKET_ORDERS_FOR_BACKTEST  = 1;  // 1 = Entry=0 (market), 0 = pending stops

// file-based debug logging
FILE*  DebugFile = 0;       // will write GoldSarDebug.csv

//------------------------------------------------------//
//  FORWARD DECLARATIONS
//------------------------------------------------------//

void  ShiftHistoryArrays();
int   IsWithinTradingSession();
int   IsNewsTime();
void  ComputeRecentMove(var nowDate, int windowSec, var *pMaxUp, var *pMaxDown);
int   CountAllOrdersForThisEA();
int   NotExistingPendingBuyStop();
int   NotExistingPendingSellStop();
var   ComputeLotSize(int mode, var riskPercent, var fixedRiskMoney, var fixedLot, int stopPoints);
var   NormalizeLot(var lot);

// Trade management function: delayed SL + pending expiry/staleness
int   SarTMF(var placementDate);

// we'll call tick() from run()
void  tick();

// debug logging helper
void  LogDebugState(var nowDate, var barPrice, var spreadPips,
                    var moveUp, var moveDown,
                    int sarBelowBar, int sarAboveBar,
                    int longSignal, int shortSignal,
                    var lotsLogged);

//------------------------------------------------------//
//  INIT & MAIN BAR LOOP
//------------------------------------------------------//

function run()
{
	// enable optimization & log file (same idea as the simple script)
	set(PARAMETERS + LOGFILE);

	// global test / bar settings
	BarPeriod = TRADE_TIMEFRAME;  // e.g. 5-minute bars
	StartDate = 2005;             // adjust as you like
	EndDate   = 0;
	LookBack  = 200;

	// select the asset exactly as in the simple script
	asset("EUR/USD");

	// one-time initialization stuff
	if (is(INITRUN)) 
	{
		// init histories
		int i;
		for (i = 0; i < HISTORY_SIZE; i++) {
			PriceHistory[i]  = 0;
			TimeHistory[i]   = 0;
			SpreadHistory[i] = 0;
		}

		RestrictionReason = "INIT";

		// open debug CSV (overwrite each run)
		DebugFile = fopen("GoldSarDebug.csv","w");
		if (DebugFile) {
			fprintf(DebugFile,"Bar;Date;Price;SAR;SpreadPips;MoveUp;MoveDown;");
			fprintf(DebugFile,"SarBelowBar;SarAboveBar;LongSignal;ShortSignal;TotalOrders;LotMode;Lots;RestrictionReason\n");
			fflush(DebugFile);
		}
	}

	// EXITRUN cleanup
	if (is(EXITRUN)) {
		if (DEBUG_LOG)
			printf("\nExitRun: EntrySignalCount = %d",EntrySignalCount);
		if (DebugFile) {
			fclose(DebugFile);
			DebugFile = 0;
		}
		return;
	}

	//--------------------------------------------------
	// OPTIMIZED PARAMETERS (5 params total)
	//  1) SAR_STEP              – SAR sensitivity
	//     (SAR_MIN follows it)
	//  2) DRAW_BEFORE_SL_POINTS – distance before delayed SL activates
	//  3) STOP_POINTS           – fixed SL in pips
	//  4) TAKEPROFIT_POINTS     – fixed TP in pips
	//  5) MAX_HOLD_BARS         – max bar age of trade
	//--------------------------------------------------

	// 1 – SAR step (0.01 .. 0.06, step 0.01)
	SAR_STEP = optimize(0.02, 0.01, 0.06, 0.01);
	SAR_MIN  = SAR_STEP;       // tie min to step
	// SAR_MAX stays fixed at 0.20

	// 2 – delayed SL activation distance (20..120 pips, step 10)
	DRAW_BEFORE_SL_POINTS = (int)optimize(60, 20, 120, 10);

	// 3 – Fixed SL in pips (20..120, step 10)
	STOP_POINTS = (int)optimize(40, 20, 120, 10);

	// 4 – Fixed TP in pips (20..240, step 20)
	TAKEPROFIT_POINTS = (int)optimize(60, 20, 240, 20);

	// 5 – Max holding time in bars (24..288, step 24)
	MAX_HOLD_BARS = (int)optimize(72, 24, 288, 24);

	//--------------------------------------------------
	// INDICATORS (bar-based)
	//--------------------------------------------------

	// Compute current SAR on bar data (one SAR series)
	SarValue = SAR(SAR_STEP, SAR_MIN, SAR_MAX);

	// Let tick() handle trade logic
	tick();
}

//------------------------------------------------------//
//  TICK-BASED MAIN LOGIC (per incoming bar)
//------------------------------------------------------//

function tick()
{
	asset("EUR/USD");

	// ------------------------------
	// Mid price and spread
	// ------------------------------
	var mid = price();        // bar price (close)

	// Zorro's Spread is in pips for FX
	var spreadPips  = Spread;          // pips
	var spreadPrice = spreadPips*PIP;  // convert to price units

	// Approximate Bid/Ask from mid and spread in price units
	var bid = mid - 0.5*spreadPrice;
	var ask = mid + 0.5*spreadPrice;

	// Also keep a direct "price" for SAR comparison
	var barPrice = mid;

	// Current time in DATE format
	var nowDate = wdate(0);   // current bar time in Windows DATE

	// Update history (always, even during warmup)
	ShiftHistoryArrays();
	PriceHistory[0]  = bid;
	TimeHistory[0]   = nowDate;
	SpreadHistory[0] = spreadPips;

	// momentum & signal variables
	var moveUp = 0, moveDown = 0;
	int sarBelowBar = 0, sarAboveBar = 0;
	int longSignal = 0, shortSignal = 0;

	// ------------------------------
	// WARMUP: fill history & SAR first
	// ------------------------------
	if (Bar < LookBack) {
		RestrictionReason = "Warming up history";
		LogDebugState(nowDate, barPrice, spreadPips,
			0, 0, 0, 0, 0, 0, 0);
		return;
	}

	// ------------------------------
	// TIME EXIT: close trades that are too old
	// ------------------------------
	if (MAX_HOLD_BARS > 0 && (NumOpenLong > 0 || NumOpenShort > 0)) {
		int needExit = 0;
		for (open_trades) {
			int ageBars = Bar - TradeBarOpen;
			if (ageBars >= MAX_HOLD_BARS) {
				needExit = 1;
				// IMPORTANT FIX: use break_trades instead of plain break
				break_trades;
			}
		}
		if (needExit) {
			exitLong();
			exitShort();
		}
	}

	// recalc orders after possible time exits
	int totalOrders = CountAllOrdersForThisEA();

	// precompute SAR vs bar price for logging & signals
	sarBelowBar = (SarValue < barPrice);
	sarAboveBar = (SarValue > barPrice);

	// ------------------------------
	// BASIC FILTERS: SPREAD / SESSION / NEWS
	// ------------------------------	
	if (!RELAX_FILTERS_FOR_BACKTEST && spreadPips > MAX_SPREAD_POINTS) {
		RestrictionReason = "Spread too high";
		LogDebugState(nowDate, barPrice, spreadPips,
			moveUp, moveDown, sarBelowBar, sarAboveBar, 0, 0, 0);
		return;
	}

	if (!RELAX_FILTERS_FOR_BACKTEST && !IsWithinTradingSession()) {
		RestrictionReason = "Outside trading session";
		LogDebugState(nowDate, barPrice, spreadPips,
			moveUp, moveDown, sarBelowBar, sarAboveBar, 0, 0, 0);
		return;
	}

	if (!RELAX_FILTERS_FOR_BACKTEST && USE_NEWS_FILTER && IsNewsTime()) {
		RestrictionReason = "News filter active";
		LogDebugState(nowDate, barPrice, spreadPips,
			moveUp, moveDown, sarBelowBar, sarAboveBar, 0, 0, 0);
		return;
	}

	RestrictionReason = "OK";

	// ------------------------------
	// MOMENTUM CHECK (bar-based)
	// ------------------------------
	ComputeRecentMove(nowDate, ACTIVATE_WINDOW_SEC, &moveUp, &moveDown);

	if (!RELAX_FILTERS_FOR_BACKTEST && ACTIVATE_MOVE_POINTS > 0) { 
		if (moveUp < ACTIVATE_MOVE_POINTS && fabs(moveDown) < ACTIVATE_MOVE_POINTS) {
			RestrictionReason = "Not enough momentum";
			LogDebugState(nowDate, barPrice, spreadPips,
				moveUp, moveDown, sarBelowBar, sarAboveBar, 0, 0, 0);
			return;
		}
	}

	// ------------------------------
	// SAR VALUE & TREND BIAS
	// ------------------------------
	if (SarValue == 0) {
		RestrictionReason = "SAR unavailable";
		LogDebugState(nowDate, barPrice, spreadPips,
			moveUp, moveDown, sarBelowBar, sarAboveBar, 0, 0, 0);
		return;
	}

	// ------------------------------
	// BUILD SIGNALS (LONG / SHORT)
	// ------------------------------
	longSignal  = sarBelowBar;
	shortSignal = sarAboveBar;

	if (!RELAX_FILTERS_FOR_BACKTEST && ACTIVATE_MOVE_POINTS > 0) {
		if (longSignal && moveUp < ACTIVATE_MOVE_POINTS)
			longSignal = 0;
		if (shortSignal && fabs(moveDown) < ACTIVATE_MOVE_POINTS)
			shortSignal = 0;
	}

	// ------------------------------
	// EXIT LOGIC: flip on opposite SAR signal
	// ------------------------------
	if (NumOpenLong > 0 && shortSignal)
		exitLong();
	if (NumOpenShort > 0 && longSignal)
		exitShort();

	// recalc after flip exits
	totalOrders = CountAllOrdersForThisEA();

	// ------------------------------
	// DEBUG: entry condition monitoring
	// ------------------------------
	if (longSignal) {
		EntrySignalCount++;
		if (DEBUG_LOG) {
			printf("\nBar %d LONG signal: moveUp=%.1f, SAR=%.5f, bid=%.5f, ask=%.5f, barPrice=%.5f",
				Bar, moveUp, SarValue, bid, ask, barPrice);
		}
	}
	if (shortSignal) {
		EntrySignalCount++;
		if (DEBUG_LOG) {
			printf("\nBar %d SHORT signal: moveDown=%.1f, SAR=%.5f, bid=%.5f, ask=%.5f, barPrice=%.5f",
				Bar, moveDown, SarValue, bid, ask, barPrice);
		}
	}

	// ------------------------------
	// PLACE BUY / SELL (market orders in backtest)
	// ------------------------------
	if (totalOrders == 0)
	{
		// Stop / TP in PRICE units
		Stop       = STOP_POINTS       * PIP;
		TakeProfit = TAKEPROFIT_POINTS * PIP;
		Trail      = 0;
		OrderDuration = PENDING_EXPIRE_SEC;

		// BUY
		if (longSignal) {
			int stopPointsB = DRAW_BEFORE_SL_POINTS + EXTRA_SL_BUFFER_POINTS;

			var lotB = 1;
			Lots  = lotB;

			if (USE_MARKET_ORDERS_FOR_BACKTEST)
				Entry = 0;
			else
				Entry = SAR_BUFFER_POINTS; // pips offset if you ever use pending

			if (DEBUG_LOG) {
				printf("\nBar %d  enterLong: Lots=%.2f EntryOffset=%g stopPoints=%d StopPips=%d TPpips=%d",
					Bar, Lots, (var)Entry, stopPointsB, STOP_POINTS, TAKEPROFIT_POINTS);
			}

			enterLong(SarTMF, nowDate);

			LogDebugState(nowDate, barPrice, spreadPips,
				moveUp, moveDown, sarBelowBar, sarAboveBar,
				longSignal, shortSignal, Lots);

			return;
		}

		// SELL
		if (shortSignal) {
			int stopPointsS = DRAW_BEFORE_SL_POINTS + EXTRA_SL_BUFFER_POINTS;

			var lotS = 1;
			Lots  = lotS;

			if (USE_MARKET_ORDERS_FOR_BACKTEST)
				Entry = 0;
			else
				Entry = SAR_BUFFER_POINTS;

			if (DEBUG_LOG) {
				printf("\nBar %d  enterShort: Lots=%.2f EntryOffset=%g stopPoints=%d StopPips=%d TPpips=%d",
					Bar, Lots, (var)Entry, stopPointsS, STOP_POINTS, TAKEPROFIT_POINTS);
			}

			enterShort(SarTMF, nowDate);

			LogDebugState(nowDate, barPrice, spreadPips,
				moveUp, moveDown, sarBelowBar, sarAboveBar,
				longSignal, shortSignal, Lots);

			return;
		}
	}

	// no trade placed on this bar -> log state
	LogDebugState(nowDate, barPrice, spreadPips,
		moveUp, moveDown, sarBelowBar, sarAboveBar,
		0, 0, 0);
}

//------------------------------------------------------//
//  DEBUG LOGGING HELPER
//------------------------------------------------------//

void LogDebugState(var nowDate, var barPrice, var spreadPips,
                   var moveUp, var moveDown,
                   int sarBelowBar, int sarAboveBar,
                   int longSignal, int shortSignal,
                   var lotsLogged)
{
	if (!DebugFile || Bar < LookBack)
		return;

	fprintf(DebugFile,
		"%d;%.6f;%.5f;%.5f;%.1f;%.1f;%.1f;%d;%d;%d;%d;%d;%d;%.2f;%s\n",
		Bar, nowDate, barPrice, SarValue, spreadPips,
		moveUp, moveDown,
		sarBelowBar, sarAboveBar,
		longSignal, shortSignal,
		CountAllOrdersForThisEA(),
		LotMode, lotsLogged,
		RestrictionReason
	);
	fflush(DebugFile);
}

//------------------------------------------------------//
//  HISTORY SHIFT
//------------------------------------------------------//

void ShiftHistoryArrays()
{
	int i;
	for (i = HISTORY_SIZE-1; i > 0; i--) {
		PriceHistory[i]  = PriceHistory[i-1];
		TimeHistory[i]   = TimeHistory[i-1];
		SpreadHistory[i] = SpreadHistory[i-1];
	}
}

//------------------------------------------------------//
//  SESSION FILTER (hour-based)
//------------------------------------------------------//

int IsWithinTradingSession()
{
	if (SESSION_START_HOUR == SESSION_END_HOUR)
		return 1;

	int hourNow = hour(0);   // bar/tick time in BarZone

	if (SESSION_START_HOUR < SESSION_END_HOUR) {
		if (hourNow >= SESSION_START_HOUR && hourNow < SESSION_END_HOUR)
			return 1;
		else
			return 0;
	} else {
		if (hourNow >= SESSION_START_HOUR || hourNow < SESSION_END_HOUR)
			return 1;
		else
			return 0;
	}
}

//------------------------------------------------------//
//  NEWS FILTER – STUB
//------------------------------------------------------//

int IsNewsTime()
{
	if (!USE_NEWS_FILTER)
		return 0;

	return 0;
}

//------------------------------------------------------//
//  RECENT PRICE MOVE (bar-based window derived from seconds)
//------------------------------------------------------//

void ComputeRecentMove(var nowDate, int windowSec, var *pMaxUp, var *pMaxDown)
{
	var maxUp   = 0;
	var maxDown = 0;

	var secondsPerBar = 60*TRADE_TIMEFRAME;      // e.g. 5min -> 300s
	int windowBars = (int)(windowSec / secondsPerBar);
	if (windowBars < 1) windowBars = 1;
	if (windowBars >= HISTORY_SIZE) windowBars = HISTORY_SIZE-1;

	var refPrice = PriceHistory[0];

	int i;
	for (i = 1; i <= windowBars; i++) {
		if (PriceHistory[i] == 0)
			continue;

		var deltaPoints = (refPrice - PriceHistory[i]) / PIP; // in pips

		if (deltaPoints > maxUp)
			maxUp = deltaPoints;
		if (deltaPoints < maxDown)
			maxDown = deltaPoints;
	}

	*pMaxUp   = maxUp;
	*pMaxDown = maxDown;
}

//------------------------------------------------------//
//  LOT SIZE CALCULATION (using PIPCost)
//------------------------------------------------------//

var ComputeLotSize(int mode,
                   var riskPercent,
                   var fixedRiskMoney,
                   var fixedLot,
                   int stopPoints)
{
	if (stopPoints <= 0) {
		return NormalizeLot(fixedLot);
	}

	var riskPerLotMoney = stopPoints * PIPCost;
	var lot;

	if (mode == LOT_FIXED_LOT) {
		lot = fixedLot;
	} 
	else if (mode == LOT_BALANCE_PERCENT) {
		var accBal = Balance;
		var maxRiskMoney = accBal * (riskPercent/100.);
		lot = maxRiskMoney / riskPerLotMoney;
	} 
	else if (mode == LOT_EQUITY_PERCENT) {
		var accEq  = Equity;
		var maxRiskMoney = accEq * (riskPercent/100.);
		lot = maxRiskMoney / riskPerLotMoney;
	} 
	else if (mode == LOT_FIXED_RISK_MONEY) {
		lot = fixedRiskMoney / riskPerLotMoney;
	} 
	else {
		lot = fixedLot;
	}

	return NormalizeLot(lot);
}

//------------------------------------------------------//
//  LOT NORMALIZATION – basic integer clipping
//------------------------------------------------------//

var NormalizeLot(var lot)
{
	if (lot <= 0)
		return 0;

	if (lot < 1)
		lot = 1;

	lot = floor(lot);
	return lot;
}

//------------------------------------------------------//
//  ORDER COUNT FOR THIS SCRIPT / ASSET
//------------------------------------------------------//

int CountAllOrdersForThisEA()
{
	return NumOpenLong + NumOpenShort + NumPendingLong + NumPendingShort;
}

//------------------------------------------------------//
//  EXISTING PENDING CHECKS
//------------------------------------------------------//

int NotExistingPendingBuyStop()
{
	if (NumPendingLong > 0)
		return 0;
	return 1;
}

int NotExistingPendingSellStop()
{
	if (NumPendingShort > 0)
		return 0;
	return 1;
}

//------------------------------------------------------//
//  TMF: MANAGE OPEN & PENDING TRADES
//------------------------------------------------------//

int SarTMF(var placementDate)
{
	var nowDate = wdate(0);
	var ageSec  = (nowDate - placementDate) * 24*60*60;

	// ---- Pending trades: expiry & staleness ----
	if (TradeIsPending) {
		// Could use ageSec, STALE_WINDOW_SEC, etc. if you
		// re-enable pending orders.
		return 0;
	}

	// ---- Open trades: delayed SL activation ----
	if (TradeIsOpen) {
		if (TradeStopLimit == 0.) {
			var curPrice = price();
			var lossPoints;

			if (TradeIsLong)
				lossPoints = (TradePriceOpen - curPrice) / PIP;
			else
				lossPoints = (curPrice - TradePriceOpen) / PIP;

			if (lossPoints >= DRAW_BEFORE_SL_POINTS) {
				if (TradeIsLong)
					TradeStopLimit = curPrice - EXTRA_SL_BUFFER_POINTS*PIP;
				else
					TradeStopLimit = curPrice + EXTRA_SL_BUFFER_POINTS*PIP;
			}
		}
	}

	return 0;
}

Last edited by TipmyPip; 11/19/25 10:35.
Adaptive Slope Trend [Re: TipmyPip] #489002
11/29/25 08:58
11/29/25 08:58
Joined: Sep 2017
Posts: 181
TipmyPip Online OP
Member
TipmyPip  Online OP
Member

Joined: Sep 2017
Posts: 181
This script implements a basic trend-following trading strategy on the EUR/USD pair using 15-minute bars, enhanced with a custom linear regression slope calculation for precise trend detection. The price series is analyzed using a 20-period simple moving average and a 14-period RSI, which is normalized between 0 and 1 for threshold-based decision-making. Instead of relying on Zorro’s built-in slope()—which uses an undocumented, fixed internal period—the script defines a custom slopeN() function, allowing dynamic control over the regression window (in this case, 10 bars). This flexibility enables fine-tuning and optimization, which is crucial for adapting to varying market conditions. The strategy enters a long position when the price crosses above the moving average and the RSI indicates the market is not overbought. Risk controls are introduced using the ATR to calculate stop levels and clamp the trade volume, ensuring trades remain within defined bounds. The approach demonstrates how integrating custom statistical functions in lite-C enhances Zorro's built-in capabilities for more adaptable and data-driven trading logic.


Code
var slopeN(vars Data, int Period)
{
	var SX = 0, SY = 0, SXY = 0, SXX = 0;
	int i;
	for(i = 0; i < Period; i++) {
		SX += i;
		SY += Data[i];
		SXY += i*Data[i];
		SXX += i*i;
	}
	var Nom = Period*SXY - SX*SY;
	var Denom = Period*SXX - SX*SX;
	if(Denom == 0.) return 0.;
	return Nom / Denom;
}

function run() 
{
	set(PARAMETERS);
	BarPeriod = 15;
	StartDate = 20220101;
	asset("EUR/USD");

	vars Price = series(priceClose());
	var sma = SMA(Price, 20);
	var rsi = RSI(Price, 14);

	var slopeVal = slopeN(Price, 10);

	var trend = sign(slopeVal);
	var risk = slider(1, 5000, 1000, 10000, "Risk", "Risk setting");
	var atr = ATR(14);
	var stopLevel = clamp(atr*2, 10, 50);
	var normRSI = clamp(rsi/100, 0, 1);
	var tradeVol = clamp(10000 / fix0(atr), 1, 5);

	if(crossOver(Price, sma) && normRSI < 0.7)
		enterLong();

	plot("RSI", normRSI, NEW, RED);
}

RegSlope Adaptive Control Slope Trend [Re: TipmyPip] #489003
11/29/25 09:38
11/29/25 09:38
Joined: Sep 2017
Posts: 181
TipmyPip Online OP
Member
TipmyPip  Online OP
Member

Joined: Sep 2017
Posts: 181
This script implements a fully panel-driven EUR/USD trend-following strategy that uses a custom linear regression slope as its main trend filter and exposes all key parameters through a Zorro control panel. The LinearRegressionSlope function computes the slope of a regression line over a configurable number of bars (SlopePeriod), and this slope is used, together with a configurable SMA (SmaPeriod) and RSI (RsiPeriod), to assess trend and overbought/oversold conditions. Global parameters define whether trading is enabled, the risk per trade as a percentage of equity, ATR period and ATR-based stop multiplier, as well as minimum and maximum stop distances and position sizes. A click handler reacts to user edits in the panel: it toggles trading on/off, updates numeric parameters entered in the panel cells, and provides a “ResetEq” button to reset capital for demo/testing. In run(), all parameters are first sanitized with clamp() to keep them within sensible bounds, then indicators (SMA, RSI, ATR) and the regression slope are calculated, the slope is displayed in the panel, and position size is derived from risk percent, equity, and stop size. The panel is created once at INITRUN with labeled rows for each parameter and updated every bar for the live slope value, while the trading logic simply enters a long position when trading is enabled, price crosses above the SMA, and normalized RSI is below 0.7, plotting the normalized RSI for visual monitoring.

Code
//////////////////////////////////////////////////////////
// Linear regression slope with custom period
//////////////////////////////////////////////////////////
var LinearRegressionSlope(vars Data, int Period)
{
	var sumX = 0;
	var sumY = 0;
	var sumXY = 0;
	var sumX2 = 0;
	int i;

	for(i = 0; i < Period; i++) {
		sumX += i;
		sumY += Data[i];
		sumXY += i * Data[i];
		sumX2 += i * i;
	}

	var numerator = Period * sumXY - sumX * sumY;
	var denominator = Period * sumX2 - sumX * sumX;

	if(denominator != 0)
		return numerator / denominator;
	else
		return 0;
}

//////////////////////////////////////////////////////////
// Global Parameters (editable via panel)
//////////////////////////////////////////////////////////

int EnableTrade    = 1;    // trading on/off
var InputRiskPct   = 1.0;  // risk per trade in percent

int SlopePeriod    = 10;   // bars used for regression slope
int SmaPeriod      = 20;   // SMA period
int RsiPeriod      = 14;   // RSI period
int AtrPeriod      = 14;   // ATR period

var StopATRMult    = 2.0;  // stop = ATR * this
var StopMin        = 10;   // min stop (price distance)
var StopMax        = 50;   // max stop

var PosMin         = 1;    // min position size
var PosMax         = 5;    // max position size

var DisplaySlope   = 0;    // for live slope display in the panel

//////////////////////////////////////////////////////////
// Click handler for panel interactions
//////////////////////////////////////////////////////////
function click(int row,int col)
{
	string Text;

	if(!is(RUNNING)) return;   // ignore when script not running
	if(row < 0) return;        // ignore Result/Action/Asset events

	Text = panelGet(row,col);

	// Row / column mapping
	// 0: Enable trading (button)
	// 1: Risk %
	// 2: Slope period
	// 3: SMA period
	// 4: RSI period
	// 5: ATR period
	// 6: Stop ATR mult
	// 7: Stop min
	// 8: Stop max
	// 9: Pos min
	// 10: Pos max
	// 11: Reset equity button

	if(row == 0 && col == 1) {
		// Toggle trading
		if(EnableTrade)
			EnableTrade = 0;
		else
			EnableTrade = 1;

		panelSet(0,1, ifelse(EnableTrade,"On","Off"),0,0,4);
	}
	else if(row == 1 && col == 1) {
		InputRiskPct = atof(Text);
	}
	else if(row == 2 && col == 1) {
		SlopePeriod = atoi(Text);
	}
	else if(row == 3 && col == 1) {
		SmaPeriod = atoi(Text);
	}
	else if(row == 4 && col == 1) {
		RsiPeriod = atoi(Text);
	}
	else if(row == 5 && col == 1) {
		AtrPeriod = atoi(Text);
	}
	else if(row == 6 && col == 1) {
		StopATRMult = atof(Text);
	}
	else if(row == 7 && col == 1) {
		StopMin = atof(Text);
	}
	else if(row == 8 && col == 1) {
		StopMax = atof(Text);
	}
	else if(row == 9 && col == 1) {
		PosMin = atof(Text);
	}
	else if(row == 10 && col == 1) {
		PosMax = atof(Text);
	}
	else if(row == 11 && col == 0) {
		// Reset equity button
		Capital = 100000; // demo reset
	}
}

//////////////////////////////////////////////////////////
// Main strategy
//////////////////////////////////////////////////////////
function run() 
{
	vars Price;
	var sma, rsi, slopeVal, trend, atr, stopLevel, normRSI;
	var tradeRisk, posSize;
	string txt;

	set(PARAMETERS);
	BarPeriod = 15;
	StartDate = 20220101;
	asset("EUR/USD");

	// Clamp and sanitize parameter ranges to avoid nonsense
	SlopePeriod = clamp(SlopePeriod, 5, 200);
	SmaPeriod   = clamp(SmaPeriod,   2, 200);
	RsiPeriod   = clamp(RsiPeriod,   2, 200);
	AtrPeriod   = clamp(AtrPeriod,   2, 200);

	StopATRMult = clamp(StopATRMult, 0.5, 10);
	StopMin     = clamp(StopMin,     1,  500);
	StopMax     = clamp(StopMax,     StopMin, 1000);

	PosMin      = clamp(PosMin, 0.01, 100);
	PosMax      = clamp(PosMax, PosMin, 1000);

	InputRiskPct = clamp(InputRiskPct, 0.1, 20); // 0.1% .. 20%

	Price = series(priceClose());
	sma   = SMA(Price, SmaPeriod);
	rsi   = RSI(Price, RsiPeriod);

	slopeVal    = LinearRegressionSlope(Price, SlopePeriod);
	DisplaySlope = slopeVal;
	trend       = sign(slopeVal);

	atr       = ATR(AtrPeriod);
	stopLevel = clamp(atr * StopATRMult, StopMin, StopMax);
	normRSI   = clamp(rsi / 100, 0, 1);

	// Risk-based position sizing using percentage from panel
	tradeRisk = InputRiskPct / 100 * Equity;
	posSize   = clamp(tradeRisk / fix0(stopLevel), PosMin, PosMax);

	// Panel setup only once at init
	if(is(INITRUN))
	{
		// 12 rows, 2 columns, default color (0), cell width 80 px
		panel(12,2,0,80);

		// Row 0: Enable trading button
		panelSet(0,0,"Enable",0,0,1);
		panelSet(0,1, ifelse(EnableTrade,"On","Off"),0,0,4);

		// Row 1: Risk %
		panelSet(1,0,"Risk %",0,0,1);
		txt = strf("%.2f",InputRiskPct);
		panelSet(1,1,txt,0,0,2);

		// Row 2: Slope period
		panelSet(2,0,"SlopePer",0,0,1);
		txt = strf("%i",SlopePeriod);
		panelSet(2,1,txt,0,0,2);

		// Row 3: SMA period
		panelSet(3,0,"SMA Per",0,0,1);
		txt = strf("%i",SmaPeriod);
		panelSet(3,1,txt,0,0,2);

		// Row 4: RSI period
		panelSet(4,0,"RSI Per",0,0,1);
		txt = strf("%i",RsiPeriod);
		panelSet(4,1,txt,0,0,2);

		// Row 5: ATR period
		panelSet(5,0,"ATR Per",0,0,1);
		txt = strf("%i",AtrPeriod);
		panelSet(5,1,txt,0,0,2);

		// Row 6: Stop ATR mult
		panelSet(6,0,"Stop xATR",0,0,1);
		txt = strf("%.2f",StopATRMult);
		panelSet(6,1,txt,0,0,2);

		// Row 7: Stop min
		panelSet(7,0,"StopMin",0,0,1);
		txt = strf("%.2f",StopMin);
		panelSet(7,1,txt,0,0,2);

		// Row 8: Stop max
		panelSet(8,0,"StopMax",0,0,1);
		txt = strf("%.2f",StopMax);
		panelSet(8,1,txt,0,0,2);

		// Row 9: Pos min
		panelSet(9,0,"PosMin",0,0,1);
		txt = strf("%.2f",PosMin);
		panelSet(9,1,txt,0,0,2);

		// Row 10: Pos max
		panelSet(10,0,"PosMax",0,0,1);
		txt = strf("%.2f",PosMax);
		panelSet(10,1,txt,0,0,2);

		// Row 11: Reset + Slope display (label; value updated each bar)
		panelSet(11,0,"ResetEq",0,0,4);
		txt = strf("%.4f",DisplaySlope);
		panelSet(11,1,txt,0,0,1);
	}

	// Update slope display every bar
	txt = strf("%.4f",DisplaySlope);
	panelSet(11,1,txt,0,0,1);

	// Trading logic
	if(EnableTrade && crossOver(Price, sma) && normRSI < 0.7)
		enterLong(posSize);

	plot("RSI", normRSI, NEW, RED);
}

Entropy Edge Learner (EEL) [Re: TipmyPip] #489101
01/20/26 07:17
01/20/26 07:17
Joined: Sep 2017
Posts: 181
TipmyPip Online OP
Member
TipmyPip  Online OP
Member

Joined: Sep 2017
Posts: 181
An ML-driven EUR/USD strategy that treats the market as an information process: it measures the Shannon entropy of recent up/down returns (how “random” vs “structured” the tape looks), combines it with recent drift and volatility, and uses Zorro’s built-in adviseLong() machine learning to predict the next-day return and scale long/short exposure accordingly.

Code
// ============================================================================
// Shiller_EURUSD_EntropyML_HistoryBounds.c — Zorro / lite-C (EUR/USD)
// ============================================================================

function run()
{
    // ------------------------------------------------------------------------
    // SESSION / DATA SETTINGS  (SET THESE BEFORE asset()!)
    // ------------------------------------------------------------------------
    BarPeriod = 1440;      // 1 day bars

    // "Use whatever history is available":
    // StartDate earlier than history -> clamps to first bar.
    // EndDate = 0 -> runs to end of available history by default.
    StartDate = 20250101;
    EndDate   = 0;

    LookBack  = 250;

    // RULES required for advise* ML training/loading
    set(PLOTNOW|RULES);

    asset("EUR/USD");
    algo("EntropyML");

    // ------------------------------------------------------------------------
    // PRICE SERIES
    // ------------------------------------------------------------------------
    var  eps = 1e-12;
    vars P   = series(priceClose());
    vars R1  = series(log(max(eps,P[0]) / max(eps,P[1])));

    // ------------------------------------------------------------------------
    // "DIVIDEND" / CARRY PROXY (Part A)
    // ------------------------------------------------------------------------
    var  carryDaily = 0.015/252.;
    vars D = series(carryDaily);

    // ------------------------------------------------------------------------
    // Create feature series UNCONDITIONALLY (good practice)
    // ------------------------------------------------------------------------
    vars EntS   = series(0);
    vars StdevS = series(0);
    vars MeanRS = series(0);

    // =========================================================================
    // PART A: Excess volatility illustration (scaled down)
    // =========================================================================
    int  Kmax = 60;
    var  r_d  = 0.0001;
    vars Px   = series(0);

    if (Bar > LookBack)
    {
        var sumDisc = 0;
        var disc    = 1;
        int k;

        for (k = 1; k <= Kmax; k++)
        {
            disc   /= (1 + r_d);
            sumDisc += disc * D[k];
        }
        Px[0] = sumDisc;

        int W = 80;
        if (Bar > LookBack + Kmax + W)
        {
            var meanP = 0, meanPx = 0;
            int i;

            for (i = 0; i < W; i++) { meanP += P[i]; meanPx += Px[i]; }
            meanP  /= (var)W;
            meanPx /= (var)W;

            var varP = 0, varPx = 0;
            for (i = 0; i < W; i++)
            {
                var a = P[i]  - meanP;
                var b = Px[i] - meanPx;
                varP  += a*a;
                varPx += b*b;
            }
            varP  /= (var)(W-1);
            varPx /= (var)(W-1);

            plot("Var(P)",  varP,  NEW, 0);
            plot("Var(P*)", varPx, 0,   0);

            if (Bar % 20 == 0)
                printf("\n[EXCESS VOL] W=%d Var(P)=%.6g Var(P*)=%.6g ratio=%.3f",
                    W, varP, varPx, varP/(varPx + eps));
        }
    }

    // =========================================================================
    // PART B: ENTROPY + MACHINE LEARNING (adviseLong)
    // =========================================================================
    int Wml = 60;
    if (Bar > LookBack + Wml + 5)
    {
        int up = 0, down = 0;
        int i;

        for (i = 1; i <= Wml; i++)
        {
            if (R1[i] > 0) up++;
            else if (R1[i] < 0) down++;
        }

        var p_up = ifelse((up + down) > 0, (var)up / (var)(up + down), 0.5);
        var p_dn = 1 - p_up;

        var entropy = 0;
        if (p_up > 0 && p_dn > 0)
            entropy = -p_up*log(p_up) - p_dn*log(p_dn);

        var meanR = 0;
        for (i = 1; i <= Wml; i++) meanR += R1[i];
        meanR /= (var)Wml;

        var varR = 0;
        for (i = 1; i <= Wml; i++)
        {
            var d = R1[i] - meanR;
            varR += d*d;
        }
        var stdev = sqrt(max(eps, varR/(var)(Wml-1)));

        EntS[0]   = entropy;
        StdevS[0] = stdev;
        MeanRS[0] = meanR;

        int Method = PERCEPTRON + FUZZY + BALANCED;

        var Objective = R1[0];
        int Offset = ifelse(Train, 1, 0);

        var Prediction = adviseLong(Method, Objective,
            EntS[Offset], StdevS[Offset], MeanRS[Offset]);

        var Lev = clamp(Prediction * 10, -0.5, 0.5);

        if (Lev > 0.05)       { exitShort(); enterLong();  Lots = 1; }
        else if (Lev < -0.05) { exitLong();  enterShort(); Lots = 1; }
        else                  { exitLong();  exitShort(); }

        plot("Entropy", entropy, NEW, 0);
        plot("Pred",    Prediction, 0, 0);
        plot("Lev",     Lev, 0, 0);
    }
}

Last edited by TipmyPip; 01/20/26 07:18.
EigenGlyph Cascade [Re: TipmyPip] #489107
7 hours ago
7 hours ago
Joined: Sep 2017
Posts: 181
TipmyPip Online OP
Member
TipmyPip  Online OP
Member

Joined: Sep 2017
Posts: 181
EigenGlyph Cascade is a trading strategy that treats the market like a living expression that can be simplified, transformed, and interpreted through symbolic reasoning. Instead of staring at price as raw numbers, it constructs a compact “language” of market behavior by translating two time scales into a small set of descriptive tokens. Each token represents a structural property of the recent price narrative, the way a symbolic mathematician would reduce a complicated statement into a more meaningful form.

At its core, the strategy builds two parallel views of the same instrument, a fast lens and a slow lens. From each lens it derives a picture of how returns relate to their own delayed echoes. This creates a small relationship structure that can be read like a symbolic object: it has intensity, balance, and alignment. The intensity reflects how strongly one pattern dominates the others, similar to how a rewritten expression may reveal a leading term. The balance reflects the overall “size” of variation in that relationship, like the total weight of terms in a simplified form. The alignment reflects how consistently the present and delayed behaviors move together, like whether two parts of an expression reinforce or cancel each other.

Alongside this, EigenGlyph Cascade adds a second symbolic layer inspired by valuation logic. It builds a discounted reference track from a carry assumption and compares how much the price wanders relative to that reference. This produces a stable measure of excess wandering, which behaves like a sanity check on regime behavior: some regimes are orderly, others are turbulent, and the strategy wants a vocabulary that distinguishes them.

These symbolic tokens are then normalized into a consistent scale so that a learning engine can treat them like well-formed symbols rather than mismatched magnitudes. A perceptron-based learner is used as a rule synthesizer: during training it “writes” a mapping from tokens to directional preference, guided by realized outcomes. During trading it “reads” the current token sequence and outputs a long score and a short score, which are combined into a single decision strength. That strength is then translated into a bounded exposure command, ensuring the final action remains controlled even when the symbolic signal becomes emphatic.

In spirit, the strategy behaves like a symbolic pipeline: observe, encode, simplify, infer, and act. It does not attempt to predict the market as a closed-form truth. Instead, it continuously rewrites the incoming price story into a small symbolic summary, and trades based on the meaning of that summary across two time scales.

Code
// ============================================================================
// EIG2TF - OPT
//
// Strategy overview
// ---------------
// This strategy trades EUR/USD using a two-timeframe feature set that combines:
//
// (1) A valuation-style volatility ratio (EV)
//     - Builds a discounted cashflow proxy Px* from a constant carry approximation.
//     - Computes EV = Var(P) / Var(Px*), a relative “excess volatility” measure.
//
// (2) A 2D covariance eigen-structure (“Eigen dominance”)
//     - Uses lagged return pairs (R[t], R[t+L]) to build a 2×2 covariance matrix.
//     - Extracts:
//         Dom  = ?max / ?min   (dominant eigenvalue ratio; anisotropy / regime strength)
//         Tr   = ?1 + ?2       (matrix trace; total variance in the 2D embedding)
//         Corr = covXY / sqrt(covXX*covYY) (correlation of the lagged return pair)
//
// (3) A machine-learning decision layer (Perceptron, fuzzy, balanced)
//     - Learns to map normalized features into long/short preferences.
//     - Training uses a returns-based objective (RETURNS), while prediction uses the
//       standard classifier output.
//     - The final trading signal is the difference between long and short scores,
//       scaled into a bounded leverage command.
//
// Data and execution model
// ------------------------
// - BarPeriod = 1440 (daily bars).
// - Two feature timeframes are used (TF1 and TF2), with TF2 constrained to be > TF1.
// - A warmup period is enforced to ensure all rolling windows and lags are valid.
// - Training and testing/trading are separated by DataSplit (Train) and full-data
//   evaluation (Test/Trade).
//
// Parameterization
// ----------------
// The strategy exposes a set of tunable parameters, optimized by Zorro:
//
// Timeframes
//   TF1, TF2               Feature aggregation timeframes
//
// EV construction / rolling windows
//   Kmax1, W1              Discount horizon and variance window for TF1 EV
//   Kmax2, W2              Discount horizon and variance window for TF2 EV
//
// Eigen dominance embedding
//   Weig1, L1              Covariance window and lag for TF1 eigen features
//   Weig2, L2              Covariance window and lag for TF2 eigen features
//
// Trading / risk mapping
//   LevScale               Multiplier from ML score to leverage command
//   MaxLev                 Absolute leverage cap
//   PredThr                Minimum leverage magnitude required to hold a position
//   HoldBars               Time-based exit horizon (maximum holding duration)
//   DomThr                 Regime intensity threshold for dominance logic (kept for
//                          interpretability/logging, while ML uses all features)
//
// Fixed strategy constant
//   EVThr                  A fixed EV threshold used as a reference level.
//
// Logging
// -------
// A CSV log is produced each run, containing:
// - Session metadata (timestamp, mode, bar, TFs)
// - Parameter values (optimized inputs)
// - Feature values (Dom/Tr/Corr/EV on both timeframes)
// - ML outputs (PredL, PredS, Pred) and final leverage command (Lev)
// ============================================================================

void deletePars(string Pattern)
{
    string f = file_next(Pattern);
    while(f)
    {
        file_delete(f);
        file_delete(strf("Data\\%s",f));
        f = file_next(0);
    }
    file_next(0);
}

function run()
{
    // ------------------------------------------------------------------------
    // Session setup
    // ------------------------------------------------------------------------
    BarPeriod = 1440;
    StartDate = 20100101;
    EndDate   = 0;

    set(PLOTNOW|RULES|LOGFILE|PARAMETERS);

    asset("EUR/USD");
    algo("EIG2TF_OPT15");

    var eps = 1e-12;

    // ------------------------------------------------------------------------
    // Train/Test split and effective history length
    // ------------------------------------------------------------------------
    if(Train) DataSplit = 50;
    else      DataSplit = 0;

    if(Train) LookBack = 2600;
    else      LookBack = 600;

    // ------------------------------------------------------------------------
    // Parameter file handling (per algo name)
    // ------------------------------------------------------------------------
    if(is(FIRSTINITRUN) && Train)
        deletePars("Data\\EIG2TF_OPT15*.par");

    // ------------------------------------------------------------------------
    // CSV log file initialization
    // ------------------------------------------------------------------------
    string LogFN = "Log\\EIG2TF_OPT15.csv";
    if(is(FIRSTINITRUN))
    {
        file_delete(LogFN);
        file_append(LogFN,"Date,Time,Mode,Bar,TF1,TF2,");
        file_append(LogFN,"Kmax1,W1,Weig1,L1,Kmax2,W2,Weig2,L2,");
        file_append(LogFN,"LevScale,MaxLev,PredThr,HoldBars,DomThr,EVThr,");
        file_append(LogFN,"Dom1,Tr1,Corr1,Dom2,Tr2,Corr2,EV1,EV2,");
        file_append(LogFN,"PredL,PredS,Pred,Lev\n");
    }

    // ------------------------------------------------------------------------
    // Optimized parameters (15 total)
    // ------------------------------------------------------------------------
    int TF1 = (int)optimize("TF1", 1, 1, 3, 1);
    int TF2 = (int)optimize("TF2", 5, 2, 12, 1);
    if(TF2 <= TF1) TF2 = TF1 + 1;
    if(TF2 > 12)   TF2 = 12;

    int Kmax1 = (int)optimize("Kmax1", 60, 20, 120, 1);
    int W1    = (int)optimize("W1",    80, 30, 150, 1);
    int Weig1 = (int)optimize("Weig1", 80, 30, 200, 1);
    int L1    = (int)optimize("L1",     5,  1,  20, 1);

    int Kmax2 = (int)optimize("Kmax2", 24, 10, 80,  1);
    int W2    = (int)optimize("W2",    40, 20, 120, 1);
    int Weig2 = (int)optimize("Weig2", 40, 20, 150, 1);
    int L2    = (int)optimize("L2",     2,  1,  10, 1);

    var LevScale = optimize("LevScale", 10, 2, 30, 1);
    var MaxLev   = optimize("MaxLev",   0.5, 0.1, 1.0, 0.1);

    var PredThr  = optimize("PredThr",  0.02, 0.0, 0.20, 0.01);
    int HoldBars = (int)optimize("HoldBars", 5, 1, 30, 1);

    var DomThr   = optimize("DomThr",   1.5, 1.1, 5.0, 0.1);

    // Reference level for EV (kept fixed in this configuration)
    var EVThr    = 1.0;

    // ------------------------------------------------------------------------
    // Carry proxy and discount rate (constant model inputs)
    // ------------------------------------------------------------------------
    var carryDaily = 0.015/252.;
    var r_d = 0.0001;

    // ------------------------------------------------------------------------
    // Timeframe 1 series and feature buffers
    // ------------------------------------------------------------------------
    TimeFrame = TF1;

    vars P1   = series(priceClose());
    vars R1tf = series(log(max(eps,P1[0]) / max(eps,P1[1])));

    vars D1   = series(carryDaily*(var)TF1);
    vars Px1  = series(0);
    vars EV1S = series(0);

    vars Dom1S  = series(0);
    vars Tr1S   = series(0);
    vars Corr1S = series(0);

    // ------------------------------------------------------------------------
    // Timeframe 2 series and feature buffers
    // ------------------------------------------------------------------------
    TimeFrame = TF2;

    vars P2   = series(priceClose());
    vars R2tf = series(log(max(eps,P2[0]) / max(eps,P2[1])));

    vars D2   = series(carryDaily*(var)TF2);
    vars Px2  = series(0);
    vars EV2S = series(0);

    vars Dom2S  = series(0);
    vars Tr2S   = series(0);
    vars Corr2S = series(0);

    // Back to base timeframe for execution
    TimeFrame = 1;

    // ------------------------------------------------------------------------
    // Warmup: ensure all rolling windows and lags are populated
    // ------------------------------------------------------------------------
    int NeedTF1 = max(max(Kmax1, W1), (Weig1 + L1 + 2));
    int NeedTF2 = max(max(Kmax2, W2), (Weig2 + L2 + 2));
    int WarmupBars = max(TF1 * NeedTF1, TF2 * NeedTF2) + 10;
    if(Bar < WarmupBars)
        return;

    // ============================================================
    // Feature block A: EV (excess volatility proxy)
    // ============================================================
    TimeFrame = TF1;
    {
        var sumDisc1=0, disc1=1;
        int k;
        for(k=1;k<=Kmax1;k++){ disc1/=(1+r_d); sumDisc1 += disc1*D1[k]; }
        Px1[0]=sumDisc1;

        var meanP1=0, meanPx1=0; int i;
        for(i=0;i<W1;i++){ meanP1+=P1[i]; meanPx1+=Px1[i]; }
        meanP1/=W1; meanPx1/=W1;

        var varP1=0, varPx1=0;
        for(i=0;i<W1;i++){
            var a=P1[i]-meanP1, b=Px1[i]-meanPx1;
            varP1+=a*a; varPx1+=b*b;
        }
        varP1/=(W1-1); varPx1/=(W1-1);
        EV1S[0]=varP1/(varPx1+eps);
    }

    TimeFrame = TF2;
    {
        var sumDisc2=0, disc2=1;
        int k2;
        for(k2=1;k2<=Kmax2;k2++){ disc2/=(1+r_d); sumDisc2 += disc2*D2[k2]; }
        Px2[0]=sumDisc2;

        var meanP2=0, meanPx2=0; int j;
        for(j=0;j<W2;j++){ meanP2+=P2[j]; meanPx2+=Px2[j]; }
        meanP2/=W2; meanPx2/=W2;

        var varP2=0, varPx2=0;
        for(j=0;j<W2;j++){
            var a=P2[j]-meanP2, b=Px2[j]-meanPx2;
            varP2+=a*a; varPx2+=b*b;
        }
        varP2/=(W2-1); varPx2/=(W2-1);
        EV2S[0]=varP2/(varPx2+eps);
    }

    // ============================================================
    // Feature block B: Eigen dominance (Dom, Tr, Corr)
    // ============================================================
    TimeFrame = TF1;
    {
        int i; var meanX=0, meanY=0;
        for(i=1;i<=Weig1;i++){ meanX+=R1tf[i]; meanY+=R1tf[i+L1]; }
        meanX/=Weig1; meanY/=Weig1;

        var covXX=0,covYY=0,covXY=0;
        for(i=1;i<=Weig1;i++){
            var dx=R1tf[i]-meanX, dy=R1tf[i+L1]-meanY;
            covXX+=dx*dx; covYY+=dy*dy; covXY+=dx*dy;
        }
        covXX/=(Weig1-1); covYY/=(Weig1-1); covXY/=(Weig1-1);

        var trace=covXX+covYY;
        var det=covXX*covYY-covXY*covXY;
        var root=sqrt(max(0, trace*trace-4*det));

        var lam1=0.5*(trace+root), lam2=0.5*(trace-root);
        var lamMax=ifelse(lam1>=lam2,lam1,lam2);
        var lamMin=ifelse(lam1>=lam2,lam2,lam1);

        Dom1S[0]=lamMax/(lamMin+eps);
        Tr1S[0]=trace;
        Corr1S[0]=clamp(covXY/sqrt(max(eps,covXX*covYY)),-1,1);
    }

    TimeFrame = TF2;
    {
        int j; var meanX2=0, meanY2=0;
        for(j=1;j<=Weig2;j++){ meanX2+=R2tf[j]; meanY2+=R2tf[j+L2]; }
        meanX2/=Weig2; meanY2/=Weig2;

        var covXX2=0,covYY2=0,covXY2=0;
        for(j=1;j<=Weig2;j++){
            var dx2=R2tf[j]-meanX2, dy2=R2tf[j+L2]-meanY2;
            covXX2+=dx2*dx2; covYY2+=dy2*dy2; covXY2+=dx2*dy2;
        }
        covXX2/=(Weig2-1); covYY2/=(Weig2-1); covXY2/=(Weig2-1);

        var trace2=covXX2+covYY2;
        var det2=covXX2*covYY2-covXY2*covXY2;
        var root2=sqrt(max(0, trace2*trace2-4*det2));

        var lam12=0.5*(trace2+root2), lam22=0.5*(trace2-root2);
        var lamMax2=ifelse(lam12>=lam22,lam12,lam22);
        var lamMin2=ifelse(lam12>=lam22,lam22,lam12);

        Dom2S[0]=lamMax2/(lamMin2+eps);
        Tr2S[0]=trace2;
        Corr2S[0]=clamp(covXY2/sqrt(max(eps,covXX2*covYY2)),-1,1);
    }

    // ============================================================
    // ML + trading execution
    // ============================================================
    TimeFrame = 1;

    int MethodTrain = PERCEPTRON + FUZZY + BALANCED + RETURNS;
    int MethodPred  = PERCEPTRON + FUZZY + BALANCED;

    // Input normalization: keeps features comparable in scale for the perceptron.
    var Sig[8];
    Sig[0] = clamp(log(max(eps,Dom1S[0])), -2, 2);
    Sig[1] = clamp(0.25*log(max(eps,Tr1S[0])), -2, 2);
    Sig[2] = Corr1S[0];
    Sig[3] = clamp(log(max(eps,Dom2S[0])), -2, 2);
    Sig[4] = clamp(0.25*log(max(eps,Tr2S[0])), -2, 2);
    Sig[5] = Corr2S[0];
    Sig[6] = clamp(log(max(eps,EV1S[0])), -2, 2);
    Sig[7] = clamp(log(max(eps,EV2S[0])), -2, 2);

    var PredL=0, PredS=0, Pred=0, Lev=0;

    // Time-based exit: closes positions after HoldBars.
    if(NumOpenTotal > 0)
        for(open_trades)
            if(TradeIsOpen && TradeBars >= HoldBars)
                exitTrade(ThisTrade);

    // Training alternates long/short entries to produce samples for both sides.
    static int Flip = 0;

    if(Train)
    {
        if(NumOpenTotal == 0)
        {
            Flip = 1 - Flip;

            if(Flip)
            {
                adviseLong(MethodTrain,0,Sig,8);
                Lots=1; enterLong();
            }
            else
            {
                adviseShort(MethodTrain,0,Sig,8);
                Lots=1; enterShort();
            }
        }
    }
    else
    {
        // Wait until the ML rule set is available in the non-training pass.
        if(is(LOOKBACK)) return;

        PredL = adviseLong(MethodPred,0,Sig,8);
        PredS = adviseShort(MethodPred,0,Sig,8);

        // Convert long-vs-short preference into a bounded leverage target.
        Pred = (PredL - PredS) / 100.0;
        Lev  = clamp(Pred*LevScale, -MaxLev, MaxLev);

        if(Lev > PredThr)       { exitShort(); Lots=1; enterLong();  }
        else if(Lev < -PredThr) { exitLong();  Lots=1; enterShort(); }
        else                    { exitLong();  exitShort(); }
    }

    // ------------------------------------------------------------------------
    // Diagnostics and CSV log output
    // ------------------------------------------------------------------------
    string ModeStr="Trade";
    if(Train) ModeStr="Train"; else if(Test) ModeStr="Test";

    file_append(LogFN, strf("%04i-%02i-%02i,%02i:%02i,%s,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%.4f,%.3f,%.4f,%d,%.4f,%.4f,%.8f,%.8f,%.8f,%.8f,%.8f,%.8f,%.8f,%.8f,%.4f,%.4f,%.4f,%.4f\n",
        year(0),month(0),day(0), hour(0),minute(0),
        ModeStr, Bar, TF1, TF2,
        Kmax1, W1, Weig1, L1, Kmax2, W2, Weig2, L2,
        LevScale, MaxLev, PredThr, HoldBars, DomThr, EVThr,
        Dom1S[0],Tr1S[0],Corr1S[0],
        Dom2S[0],Tr2S[0],Corr2S[0],
        EV1S[0],EV2S[0],
        PredL,PredS,Pred,Lev
    ));
}

Twin Horizon Bandit Weaver [Re: TipmyPip] #489109
5 hours ago
5 hours ago
Joined: Sep 2017
Posts: 181
TipmyPip Online OP
Member
TipmyPip  Online OP
Member

Joined: Sep 2017
Posts: 181
Twin Horizon Bandit Weaver is an adaptive trading strategy that watches the market through two horizons and learns which internal settings work best as conditions change. The first horizon is the quick listener that reacts to recent movement. The second horizon is the slow listener that provides context and steadiness. These two horizons are not just different chart speeds. They are separate views of the same market story, one focused on immediate rhythm and the other focused on the broader cadence.

From each horizon, the strategy builds two families of clues. The first family is a value pressure clue that compares how price behaves versus a gently drifting reference that represents carry like influence. If price swings wildly while the reference changes smoothly, the value pressure clue becomes stronger. The second family is a structure clue that asks whether recent returns look like they are dominated by one main direction or spread across competing directions. It also captures how active the structure is overall and whether the paired return streams tend to move together or against each other.

Those horizon clues are packaged into a compact signal set and passed into a lightweight learning module that outputs a preference for long exposure and a preference for short exposure. In training mode, the strategy forces learning by taking alternating long and short trades so the learner receives outcomes and does not stall. In trading mode, it converts the two preferences into a single directional intent and then shapes that intent into a position decision.

The most distinctive feature is the parameter orchestra. Instead of fixing window lengths, thresholds, and scaling values forever, the strategy assigns one small bandit agent to each parameter. Each agent has a short menu of allowed choices. When the strategy is flat, all agents pick their choices for the next episode. Most of the time they exploit what has worked best so far, but occasionally they explore a different option to avoid getting stuck.

Rewards are taken from the realized account change when a trade closes. That reward is shared back to all bandit agents that participated in the episode, nudging their chosen settings toward or away from future selection. Risk control stays simple: trades are not allowed to linger beyond a chosen holding limit, entries require a minimum confidence threshold, and a dominance filter can require at least one horizon to show clear directional structure before allowing intent to remain active. The strategy also logs each episode so you can audit what it chose, what it saw, and how it learned.


Code
// ============================================================================
// EIG2TF - RL15 (15 bandit agents: one per parameter)
//
// FIXES INCLUDED (lite-C / Zorro):
// - No string-array initializer: ParName[] is filled by initParNames().
// - No randf(): use random(Max).
// - No NumClosedTotal: reward detected by transition (PrevOpenTotal>0 && NumOpenTotal==0),
//   reward computed as Balance - LastBalance.
// - CSV header + format strings are single literals (no split string concatenation).
// - DO NOT return during LOOKBACK in Train (otherwise forced training trades never happen).
// - Bootstrap in Test/Trade if model not trained (PredL==0 && PredS==0): open a random trade.
// ============================================================================

#define NPAR 15
#define MAXARMS 64

#define EPSILON 0.10
#define ALPHA   0.10

#define P_INT 0
#define P_VAR 1

// Parameter indices
#define P_TF1       0
#define P_TF2       1
#define P_KMAX1     2
#define P_W1        3
#define P_WEIG1     4
#define P_L1        5
#define P_KMAX2     6
#define P_W2        7
#define P_WEIG2     8
#define P_L2        9
#define P_LEVSCALE  10
#define P_MAXLEV    11
#define P_PREDTHR   12
#define P_HOLDBARS  13
#define P_DOMTHR    14

// -----------------------------
// RL/bandit storage
// -----------------------------
string ParName[NPAR];

void initParNames()
{
    ParName[P_TF1]      = "TF1";
    ParName[P_TF2]      = "TF2";
    ParName[P_KMAX1]    = "Kmax1";
    ParName[P_W1]       = "W1";
    ParName[P_WEIG1]    = "Weig1";
    ParName[P_L1]       = "L1";
    ParName[P_KMAX2]    = "Kmax2";
    ParName[P_W2]       = "W2";
    ParName[P_WEIG2]    = "Weig2";
    ParName[P_L2]       = "L2";
    ParName[P_LEVSCALE] = "LevScale";
    ParName[P_MAXLEV]   = "MaxLev";
    ParName[P_PREDTHR]  = "PredThr";
    ParName[P_HOLDBARS] = "HoldBars";
    ParName[P_DOMTHR]   = "DomThr";
}

int ParType[NPAR] =
{
    P_INT,P_INT,P_INT,P_INT,P_INT,P_INT,P_INT,P_INT,P_INT,P_INT,
    P_VAR,P_VAR,P_VAR,P_INT,P_VAR
};

// Defaults / ranges / steps
var ParDef[NPAR];
var ParMin[NPAR];
var ParMax[NPAR];
var ParStep[NPAR];

// Learned value estimates and counts
var Q[NPAR][MAXARMS];
int Ncnt[NPAR][MAXARMS];
int ArmsCount[NPAR];
int CurArm[NPAR];

// Helper: clamp arm count to MAXARMS
int calcArms(var mn, var mx, var stp)
{
    if(stp <= 0) return 1;
    int n = (int)floor((mx - mn)/stp + 1.000001);
    if(n < 1) n = 1;
    if(n > MAXARMS) n = MAXARMS;
    return n;
}

var armValue(int p, int a)
{
    var v = ParMin[p] + (var)a*ParStep[p];
    if(v < ParMin[p]) v = ParMin[p];
    if(v > ParMax[p]) v = ParMax[p];
    if(ParType[p] == P_INT) v = (var)(int)(v + 0.5);
    return v;
}

int bestArm(int p)
{
    int a, best = 0;
    var bestQ = Q[p][0];
    for(a=1; a<ArmsCount[p]; a++)
        if(Q[p][a] > bestQ) { bestQ = Q[p][a]; best = a; }
    return best;
}

int selectArm(int p)
{
    // epsilon-greedy using random(Max)
    if(random(1) < EPSILON)
        return (int)random((var)ArmsCount[p]);  // 0..ArmsCount-1
    return bestArm(p);
}

void updateArm(int p, int a, var reward)
{
    Q[p][a] = Q[p][a] + ALPHA*(reward - Q[p][a]);
    Ncnt[p][a] += 1;
}

// Initialize parameter table and RL tables
void initParams()
{
    // Keep arms <= MAXARMS
    ParDef[P_TF1] = 1;   ParMin[P_TF1] = 1;   ParMax[P_TF1] = 3;   ParStep[P_TF1] = 1;
    ParDef[P_TF2] = 5;   ParMin[P_TF2] = 2;   ParMax[P_TF2] = 12;  ParStep[P_TF2] = 1;

    ParDef[P_KMAX1] = 60; ParMin[P_KMAX1] = 20; ParMax[P_KMAX1] = 120; ParStep[P_KMAX1] = 2;
    ParDef[P_W1]    = 80; ParMin[P_W1]    = 30; ParMax[P_W1]    = 150; ParStep[P_W1]    = 2;

    ParDef[P_WEIG1] = 80; ParMin[P_WEIG1] = 30; ParMax[P_WEIG1] = 200; ParStep[P_WEIG1] = 5;
    ParDef[P_L1]    = 5;  ParMin[P_L1]    = 1;  ParMax[P_L1]    = 20;  ParStep[P_L1]    = 1;

    ParDef[P_KMAX2] = 24; ParMin[P_KMAX2] = 10; ParMax[P_KMAX2] = 80;  ParStep[P_KMAX2] = 2;
    ParDef[P_W2]    = 40; ParMin[P_W2]    = 20; ParMax[P_W2]    = 120; ParStep[P_W2]    = 2;

    ParDef[P_WEIG2] = 40; ParMin[P_WEIG2] = 20; ParMax[P_WEIG2] = 150; ParStep[P_WEIG2] = 5;
    ParDef[P_L2]    = 2;  ParMin[P_L2]    = 1;  ParMax[P_L2]    = 10;  ParStep[P_L2]    = 1;

    ParDef[P_LEVSCALE] = 10;   ParMin[P_LEVSCALE] = 2;    ParMax[P_LEVSCALE] = 30;  ParStep[P_LEVSCALE] = 1;
    ParDef[P_MAXLEV]   = 0.5;  ParMin[P_MAXLEV]   = 0.1;  ParMax[P_MAXLEV]   = 1.0; ParStep[P_MAXLEV]   = 0.1;

    ParDef[P_PREDTHR]  = 0.02; ParMin[P_PREDTHR]  = 0.00; ParMax[P_PREDTHR]  = 0.20; ParStep[P_PREDTHR] = 0.01;

    ParDef[P_HOLDBARS] = 5;    ParMin[P_HOLDBARS] = 1;    ParMax[P_HOLDBARS] = 30;  ParStep[P_HOLDBARS] = 1;

    ParDef[P_DOMTHR]   = 1.5;  ParMin[P_DOMTHR]   = 1.1;  ParMax[P_DOMTHR]   = 5.0; ParStep[P_DOMTHR]   = 0.1;

    int p, a;
    for(p=0; p<NPAR; p++)
    {
        ArmsCount[p] = calcArms(ParMin[p], ParMax[p], ParStep[p]);
        CurArm[p] = 0;
        for(a=0; a<ArmsCount[p]; a++)
        {
            Q[p][a] = 0;
            Ncnt[p][a] = 0;
        }
    }
}

// Pick new parameter actions when flat
void pickParams()
{
    int p;
    for(p=0; p<NPAR; p++)
        CurArm[p] = selectArm(p);
}

function run()
{
    // ------------------------------------------------------------------------
    // Session setup
    // ------------------------------------------------------------------------
    BarPeriod = 1440;
    StartDate = 20100101;
    EndDate   = 0;

    set(PLOTNOW|RULES|LOGFILE);

    asset("EUR/USD");
    algo("EIG2TF_RL15");

    var eps = 1e-12;

    if(Train) DataSplit = 50;
    else      DataSplit = 0;

    // IMPORTANT: keep enough history for your biggest windows
    LookBack = 2600;

    // ------------------------------------------------------------------------
    // One-time init
    // ------------------------------------------------------------------------
    static int Inited = 0;
    static int PrevOpenTotal = 0;
    static var LastBalance   = 0;

    string LogFN = "Log\\EIG2TF_RL15.csv";

    if(is(FIRSTINITRUN))
    {
        Inited = 0;
        PrevOpenTotal = 0;
        LastBalance   = 0;

        file_delete(LogFN);
        file_append(LogFN,"Date,Time,Mode,Bar,TF1,TF2,Kmax1,W1,Weig1,L1,Kmax2,W2,Weig2,L2,LevScale,MaxLev,PredThr,HoldBars,DomThr,Dom1,Tr1,Corr1,Dom2,Tr2,Corr2,EV1,EV2,PredL,PredS,Pred,Lev,Reward\n");
    }

    if(!Inited)
    {
        // optional deterministic randomness:
        // seed(12345);

        initParNames();
        initParams();
        pickParams();

        LastBalance = Balance;
        PrevOpenTotal = NumOpenTotal;

        Inited = 1;
    }

    // ------------------------------------------------------------------------
    // Convert chosen arms -> concrete parameter values
    // ------------------------------------------------------------------------
    int TF1     = (int)armValue(P_TF1, CurArm[P_TF1]);
    int TF2     = (int)armValue(P_TF2, CurArm[P_TF2]);
    if(TF2 <= TF1) TF2 = TF1 + 1;
    if(TF2 > 12)   TF2 = 12;

    int Kmax1   = (int)armValue(P_KMAX1, CurArm[P_KMAX1]);
    int W1      = (int)armValue(P_W1,    CurArm[P_W1]);
    int Weig1   = (int)armValue(P_WEIG1, CurArm[P_WEIG1]);
    int L1      = (int)armValue(P_L1,    CurArm[P_L1]);

    int Kmax2   = (int)armValue(P_KMAX2, CurArm[P_KMAX2]);
    int W2      = (int)armValue(P_W2,    CurArm[P_W2]);
    int Weig2   = (int)armValue(P_WEIG2, CurArm[P_WEIG2]);
    int L2      = (int)armValue(P_L2,    CurArm[P_L2]);

    var LevScale = armValue(P_LEVSCALE, CurArm[P_LEVSCALE]);
    var MaxLev   = armValue(P_MAXLEV,   CurArm[P_MAXLEV]);
    var PredThr  = armValue(P_PREDTHR,  CurArm[P_PREDTHR]);
    int HoldBars = (int)armValue(P_HOLDBARS, CurArm[P_HOLDBARS]);
    var DomThr   = armValue(P_DOMTHR, CurArm[P_DOMTHR]);

    // ------------------------------------------------------------------------
    // Carry proxy + discount rate
    // ------------------------------------------------------------------------
    var carryDaily = 0.015/252.;
    var r_d = 0.0001;

    // ------------------------------------------------------------------------
    // Timeframe 1 series and feature buffers
    // ------------------------------------------------------------------------
    TimeFrame = TF1;
    vars P1   = series(priceClose());
    vars R1tf = series(log(max(eps,P1[0]) / max(eps,P1[1])));
    vars D1   = series(carryDaily*(var)TF1);
    vars Px1  = series(0);
    vars EV1S = series(0);
    vars Dom1S  = series(0);
    vars Tr1S   = series(0);
    vars Corr1S = series(0);

    // ------------------------------------------------------------------------
    // Timeframe 2 series and feature buffers
    // ------------------------------------------------------------------------
    TimeFrame = TF2;
    vars P2   = series(priceClose());
    vars R2tf = series(log(max(eps,P2[0]) / max(eps,P2[1])));
    vars D2   = series(carryDaily*(var)TF2);
    vars Px2  = series(0);
    vars EV2S = series(0);
    vars Dom2S  = series(0);
    vars Tr2S   = series(0);
    vars Corr2S = series(0);

    // back to base timeframe
    TimeFrame = 1;

    // ------------------------------------------------------------------------
    // Warmup gate
    // ------------------------------------------------------------------------
    int NeedTF1 = max(max(Kmax1, W1), (Weig1 + L1 + 2));
    int NeedTF2 = max(max(Kmax2, W2), (Weig2 + L2 + 2));
    int WarmupBars = max(TF1 * NeedTF1, TF2 * NeedTF2) + 10;

    if(Bar < WarmupBars) return;

    // KEY FIX: do NOT return during LOOKBACK in Train
    if(is(LOOKBACK) && !Train) return;

    // ============================================================
    // Feature block A: EV ratios
    // ============================================================
    TimeFrame = TF1;
    {
        var sumDisc1=0, disc1=1; int k;
        for(k=1;k<=Kmax1;k++){ disc1/=(1+r_d); sumDisc1 += disc1*D1[k]; }
        Px1[0]=sumDisc1;

        var meanP1=0, meanPx1=0; int i;
        for(i=0;i<W1;i++){ meanP1+=P1[i]; meanPx1+=Px1[i]; }
        meanP1/=W1; meanPx1/=W1;

        var varP1=0, varPx1=0;
        for(i=0;i<W1;i++){
            var a=P1[i]-meanP1, b=Px1[i]-meanPx1;
            varP1+=a*a; varPx1+=b*b;
        }
        varP1/=(W1-1); varPx1/=(W1-1);
        EV1S[0]=varP1/(varPx1+eps);
    }

    TimeFrame = TF2;
    {
        var sumDisc2=0, disc2=1; int k2;
        for(k2=1;k2<=Kmax2;k2++){ disc2/=(1+r_d); sumDisc2 += disc2*D2[k2]; }
        Px2[0]=sumDisc2;

        var meanP2=0, meanPx2=0; int j;
        for(j=0;j<W2;j++){ meanP2+=P2[j]; meanPx2+=Px2[j]; }
        meanP2/=W2; meanPx2/=W2;

        var varP2=0, varPx2=0;
        for(j=0;j<W2;j++){
            var a=P2[j]-meanP2, b=Px2[j]-meanPx2;
            varP2+=a*a; varPx2+=b*b;
        }
        varP2/=(W2-1); varPx2/=(W2-1);
        EV2S[0]=varP2/(varPx2+eps);
    }

    // ============================================================
    // Feature block B: Eigen dominance
    // ============================================================
    TimeFrame = TF1;
    {
        int i; var meanX=0, meanY=0;
        for(i=1;i<=Weig1;i++){ meanX+=R1tf[i]; meanY+=R1tf[i+L1]; }
        meanX/=Weig1; meanY/=Weig1;

        var covXX=0,covYY=0,covXY=0;
        for(i=1;i<=Weig1;i++){
            var dx=R1tf[i]-meanX, dy=R1tf[i+L1]-meanY;
            covXX+=dx*dx; covYY+=dy*dy; covXY+=dx*dy;
        }
        covXX/=(Weig1-1); covYY/=(Weig1-1); covXY/=(Weig1-1);

        var trace=covXX+covYY;
        var det=covXX*covYY-covXY*covXY;
        var root=sqrt(max(0, trace*trace-4*det));

        var lam1=0.5*(trace+root), lam2=0.5*(trace-root);
        var lamMax=ifelse(lam1>=lam2,lam1,lam2);
        var lamMin=ifelse(lam1>=lam2,lam2,lam1);

        Dom1S[0]=lamMax/(lamMin+eps);
        Tr1S[0]=trace;
        Corr1S[0]=clamp(covXY/sqrt(max(eps,covXX*covYY)),-1,1);
    }

    TimeFrame = TF2;
    {
        int j; var meanX2=0, meanY2=0;
        for(j=1;j<=Weig2;j++){ meanX2+=R2tf[j]; meanY2+=R2tf[j+L2]; }
        meanX2/=Weig2; meanY2/=Weig2;

        var covXX2=0,covYY2=0,covXY2=0;
        for(j=1;j<=Weig2;j++){
            var dx2=R2tf[j]-meanX2, dy2=R2tf[j+L2]-meanY2;
            covXX2+=dx2*dx2; covYY2+=dy2*dy2; covXY2+=dx2*dy2;
        }
        covXX2/=(Weig2-1); covYY2/=(Weig2-1); covXY2/=(Weig2-1);

        var trace2=covXX2+covYY2;
        var det2=covXX2*covYY2-covXY2*covXY2;
        var root2=sqrt(max(0, trace2*trace2-4*det2));

        var lam12=0.5*(trace2+root2), lam22=0.5*(trace2-root2);
        var lamMax2=ifelse(lam12>=lam22,lam12,lam22);
        var lamMin2=ifelse(lam12>=lam22,lam22,lam12);

        Dom2S[0]=lamMax2/(lamMin2+eps);
        Tr2S[0]=trace2;
        Corr2S[0]=clamp(covXY2/sqrt(max(eps,covXX2*covYY2)),-1,1);
    }

    // back to base timeframe
    TimeFrame = 1;

    // ============================================================
    // ML + trading
    // ============================================================
    int MethodTrain = PERCEPTRON + FUZZY + BALANCED + RETURNS;
    int MethodPred  = PERCEPTRON + FUZZY + BALANCED;

    var Sig[8];
    Sig[0] = clamp(log(max(eps,Dom1S[0])), -2, 2);
    Sig[1] = clamp(0.25*log(max(eps,Tr1S[0])), -2, 2);
    Sig[2] = Corr1S[0];
    Sig[3] = clamp(log(max(eps,Dom2S[0])), -2, 2);
    Sig[4] = clamp(0.25*log(max(eps,Tr2S[0])), -2, 2);
    Sig[5] = Corr2S[0];
    Sig[6] = clamp(log(max(eps,EV1S[0])), -2, 2);
    Sig[7] = clamp(log(max(eps,EV2S[0])), -2, 2);

    // Exit after HoldBars
    if(NumOpenTotal > 0)
        for(open_trades)
            if(TradeBars >= HoldBars)
                exitTrade(ThisTrade);

    var PredL=0, PredS=0, Pred=0, Lev=0;
    static int Flip = 0;

    if(Train)
    {
        // Forced trades so ML gets samples
        if(NumOpenTotal == 0)
        {
            Flip = 1 - Flip;
            LastBalance = Balance;

            if(Flip) { adviseLong(MethodTrain,0,Sig,8); Lots=1; enterLong(); }
            else     { adviseShort(MethodTrain,0,Sig,8); Lots=1; enterShort(); }
        }
    }
    else
    {
        PredL = adviseLong(MethodPred,0,Sig,8);
        PredS = adviseShort(MethodPred,0,Sig,8);

        // Bootstrap if model not trained / no signal
        if(NumOpenTotal == 0 && PredL == 0 && PredS == 0)
        {
            LastBalance = Balance;
            if(random(1) < 0.5) { Lots=1; enterLong(); }
            else                { Lots=1; enterShort(); }
        }
        else
        {
            Pred = (PredL - PredS) / 100.0;
            Lev  = clamp(Pred*LevScale, -MaxLev, MaxLev);

            // Apply Dom filter only when signal is nonzero
            if(Lev != 0 && Dom1S[0] < DomThr && Dom2S[0] < DomThr)
                Lev = 0;

            if(Lev > PredThr)       { exitShort(); Lots=1; enterLong();  }
            else if(Lev < -PredThr) { exitLong();  Lots=1; enterShort(); }
            else                    { exitLong();  exitShort(); }
        }
    }

    // ============================================================
    // RL update: reward when going from in-position -> flat
    // ============================================================
    var Reward = 0;
    if(PrevOpenTotal > 0 && NumOpenTotal == 0)
    {
        Reward = Balance - LastBalance;

        if(Reward != 0)
        {
            int p;
            for(p=0; p<NPAR; p++)
                updateArm(p, CurArm[p], Reward);
        }

        pickParams();
        LastBalance = Balance;
    }
    PrevOpenTotal = NumOpenTotal;

    // ------------------------------------------------------------------------
    // CSV log output (single literal format string)
    // ------------------------------------------------------------------------
    string ModeStr="Trade";
    if(Train) ModeStr="Train"; else if(Test) ModeStr="Test";

    file_append(LogFN, strf("%04i-%02i-%02i,%02i:%02i,%s,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%.4f,%.3f,%.4f,%d,%.4f,%.8f,%.8f,%.8f,%.8f,%.8f,%.8f,%.8f,%.8f,%.4f,%.4f,%.4f,%.4f,%.6f\n",
        year(0),month(0),day(0), hour(0),minute(0),
        ModeStr, Bar, TF1, TF2,
        Kmax1, W1, Weig1, L1, Kmax2, W2, Weig2, L2,
        LevScale, MaxLev, PredThr, HoldBars, DomThr,
        Dom1S[0],Tr1S[0],Corr1S[0],
        Dom2S[0],Tr2S[0],Corr2S[0],
        EV1S[0],EV2S[0],
        PredL,PredS,Pred,Lev,
        Reward
    ));

    // Plots (optional)
    plot("TF1_Dom", Dom1S[0], NEW, 0);
    plot("TF2_Dom", Dom2S[0], 0, 0);
    plot("EV_TF1",  EV1S[0],  0, 0);
    plot("EV_TF2",  EV2S[0],  0, 0);
    plot("Pred",    Pred, 0, 0);
    plot("Lev",     Lev, 0, 0);
    plot("Reward",  Reward, 0, 0);
}

Fractal Bandit Compass [Re: TipmyPip] #489111
2 hours ago
2 hours ago
Joined: Sep 2017
Posts: 181
TipmyPip Online OP
Member
TipmyPip  Online OP
Member

Joined: Sep 2017
Posts: 181
FractalBandit Compass is a two layer learning strategy built for daily bar trading on EUR USD, combining adaptive parameter selection with supervised machine learning that learns from realized trade outcomes. The core idea is to let the strategy continuously reshape its own settings based on performance, while simultaneously learning when to trade using a stable set of market descriptors computed on two separate timeframes.

The first layer is a group of reinforcement learning bandit agents, one agent per strategy parameter. Each agent treats the possible settings of its parameter as a set of discrete choices, similar to selecting one option from a menu. Examples of these settings include the first timeframe choice, the offset that defines the second timeframe, window lengths for fractal dimension estimation, window lengths for slope measurement, window lengths for volatility estimation, and risk shaping controls such as leverage scaling, maximum leverage, prediction threshold, and holding time. When the system is flat and ready to begin a new trade episode, every agent selects an option using an exploration and exploitation routine. Most of the time it exploits the best known option for that parameter, but sometimes it explores alternative options to avoid getting stuck with a locally good choice that may stop working later. This makes the strategy flexible across changing regimes.

The second layer is the market signal engine, which produces a compact feature vector from two timeframes. On each timeframe, the strategy measures a Katz style fractal dimension estimate to describe how path like or trend like the recent price movement appears. It also measures a price slope over a configurable window to summarize direction and persistence, and it measures volatility using the standard deviation of log returns over a configurable window to summarize turbulence. These six values form the feature signature used by the machine learning model.

Machine learning is trained using a returns based mode so the model learns from the eventual success or failure of trades rather than from a single bar label. During training runs, the strategy forces alternating long and short entries when flat. This is not meant to be profitable by itself; it is meant to guarantee that the model sees a broad variety of examples in different market conditions and does not stall with no trades and no learning. During test and trade runs, the model produces long and short preferences from the same feature signature. If the model has not learned enough yet and outputs no meaningful preference, the strategy bootstraps a small trade using a simple directional hint from the combined slope, or a random choice when direction is unclear. This ensures the learning loop continues to generate outcomes.

The episode boundary is defined by the strategy returning to flat after having an open position. At that point, the reward is computed as the change in account balance since the start of the episode. That single reward is then used to update every bandit agent on the exact option it chose for the episode. Over time, parameter options that consistently lead to better episodes gain higher value estimates, and the agents increasingly favor them while still occasionally testing alternatives. The result is a self tuning strategy that adapts both its market interpretation settings and its execution behavior, aiming to remain robust as market structure shifts.

Code
// ============================================================================
// Fractal Learner - RL Bandits for Parameters + 2TF ML (RETURNS)
// File: Fractal_EURUSD_2TF_RL_Bandits_v1.c   (Zorro / lite-C)
//
// What changed vs optimize():
// - Replaced optimize() with epsilon-greedy multi-armed bandits (one agent per parameter).
// - When flat, agents pick new parameter "arms".
// - A trade is opened (Train: alternating long/short; Test/Trade: ML-driven + bootstrap).
// - When positions go flat again, reward = Balance delta, and all agents update Q for used arms.
// - Next episode starts with new parameter picks.
//
// lite-C safe:
// - No adjacent string literals in one file_append call (header uses multiple calls)
// - No inline/ternary helpers; uses function keyword
// - strf format string is ONE literal
// ============================================================================

#define NPAR 12
#define MAXARMS 64

#define EPSILON 0.10
#define ALPHA   0.10

#define P_INT 0
#define P_VAR 1

// Parameter indices (RL-controlled)
#define P_TF1        0
#define P_TF2D       1
#define P_FDLEN1     2
#define P_SLOPELEN1  3
#define P_VOLLEN1    4
#define P_FDLEN2     5
#define P_SLOPELEN2  6
#define P_VOLLEN2    7
#define P_LEVSCALE   8
#define P_MAXLEV     9
#define P_PREDTHR    10
#define P_HOLDBARS   11

// -----------------------------
// RL storage
// -----------------------------
string ParName[NPAR];

int ParType[NPAR] =
{
	P_INT,  // TF1
	P_INT,  // TF2d
	P_INT,  // FDLen1
	P_INT,  // SlopeLen1
	P_INT,  // VolLen1
	P_INT,  // FDLen2
	P_INT,  // SlopeLen2
	P_INT,  // VolLen2
	P_VAR,  // LevScale
	P_VAR,  // MaxLev
	P_VAR,  // PredThr
	P_INT   // HoldBars
};

var ParMin[NPAR];
var ParMax[NPAR];
var ParStep[NPAR];

var Q[NPAR][MAXARMS];
int Ncnt[NPAR][MAXARMS];
int ArmsCount[NPAR];
int CurArm[NPAR];

void initParNames()
{
	ParName[P_TF1]       = "TF1";
	ParName[P_TF2D]      = "TF2d";
	ParName[P_FDLEN1]    = "FDLen1";
	ParName[P_SLOPELEN1] = "SlopeLen1";
	ParName[P_VOLLEN1]   = "VolLen1";
	ParName[P_FDLEN2]    = "FDLen2";
	ParName[P_SLOPELEN2] = "SlopeLen2";
	ParName[P_VOLLEN2]   = "VolLen2";
	ParName[P_LEVSCALE]  = "LevScale";
	ParName[P_MAXLEV]    = "MaxLev";
	ParName[P_PREDTHR]   = "PredThr";
	ParName[P_HOLDBARS]  = "HoldBars";
}

int calcArms(var mn, var mx, var stp)
{
	if(stp <= 0) return 1;
	int n = (int)floor((mx - mn)/stp + 1.000001);
	if(n < 1) n = 1;
	if(n > MAXARMS) n = MAXARMS;
	return n;
}

var armValue(int p, int a)
{
	var v = ParMin[p] + (var)a * ParStep[p];
	if(v < ParMin[p]) v = ParMin[p];
	if(v > ParMax[p]) v = ParMax[p];
	if(ParType[p] == P_INT) v = (var)(int)(v + 0.5);
	return v;
}

int bestArm(int p)
{
	int a, best = 0;
	var bestQ = Q[p][0];
	for(a=1; a<ArmsCount[p]; a++)
	{
		if(Q[p][a] > bestQ)
		{
			bestQ = Q[p][a];
			best = a;
		}
	}
	return best;
}

int selectArm(int p)
{
	if(random(1) < EPSILON)
		return (int)random((var)ArmsCount[p]);
	return bestArm(p);
}

void updateArm(int p, int a, var reward)
{
	Q[p][a] = Q[p][a] + ALPHA*(reward - Q[p][a]);
	Ncnt[p][a] += 1;
}

void initParamsRL()
{
	// Ranges roughly matching your old optimize() ranges/steps
	ParMin[P_TF1]        = 1;    ParMax[P_TF1]        = 3;    ParStep[P_TF1]        = 1;
	ParMin[P_TF2D]       = 1;    ParMax[P_TF2D]       = 11;   ParStep[P_TF2D]       = 1;

	ParMin[P_FDLEN1]     = 20;   ParMax[P_FDLEN1]     = 220;  ParStep[P_FDLEN1]     = 5;
	ParMin[P_SLOPELEN1]  = 20;   ParMax[P_SLOPELEN1]  = 200;  ParStep[P_SLOPELEN1]  = 5;
	ParMin[P_VOLLEN1]    = 20;   ParMax[P_VOLLEN1]    = 200;  ParStep[P_VOLLEN1]    = 5;

	ParMin[P_FDLEN2]     = 10;   ParMax[P_FDLEN2]     = 160;  ParStep[P_FDLEN2]     = 5;
	ParMin[P_SLOPELEN2]  = 10;   ParMax[P_SLOPELEN2]  = 140;  ParStep[P_SLOPELEN2]  = 5;
	ParMin[P_VOLLEN2]    = 10;   ParMax[P_VOLLEN2]    = 140;  ParStep[P_VOLLEN2]    = 5;

	ParMin[P_LEVSCALE]   = 2;    ParMax[P_LEVSCALE]   = 30;   ParStep[P_LEVSCALE]   = 1;
	ParMin[P_MAXLEV]     = 0.1;  ParMax[P_MAXLEV]     = 1.0;  ParStep[P_MAXLEV]     = 0.1;
	ParMin[P_PREDTHR]    = 0.0;  ParMax[P_PREDTHR]    = 0.20; ParStep[P_PREDTHR]    = 0.01;
	ParMin[P_HOLDBARS]   = 1;    ParMax[P_HOLDBARS]   = 30;   ParStep[P_HOLDBARS]   = 1;

	int p, a;
	for(p=0; p<NPAR; p++)
	{
		ArmsCount[p] = calcArms(ParMin[p], ParMax[p], ParStep[p]);
		CurArm[p] = 0;
		for(a=0; a<ArmsCount[p]; a++)
		{
			Q[p][a] = 0;
			Ncnt[p][a] = 0;
		}
	}
}

void pickParams()
{
	int p;
	for(p=0; p<NPAR; p++)
		CurArm[p] = selectArm(p);
}

// -----------------------------
// Feature helpers (your originals, lite-C safe)
// -----------------------------

function fractalDimKatz(vars P, int N)
{
	if(N < 2) return 1.0;

	var L = 0;
	int i;
	for(i=0; i<N-1; i++)
		L += abs(P[i] - P[i+1]);

	var d = 0;
	for(i=1; i<N; i++)
	{
		var di = abs(P[i] - P[0]);
		if(di > d) d = di;
	}

	if(L <= 0 || d <= 0) return 1.0;

	var n  = (var)N;
	var fd = log(n) / (log(n) + log(d / L));
	return clamp(fd, 1.0, 2.0);
}

function linSlope(vars P, int N)
{
	if(N < 2) return 0;

	var sumT=0, sumP=0, sumTT=0, sumTP=0;
	int i;
	for(i=0; i<N; i++)
	{
		var t = (var)i;
		sumT  += t;
		sumP  += P[i];
		sumTT += t*t;
		sumTP += t*P[i];
	}

	var denom = (var)N*sumTT - sumT*sumT;
	if(abs(denom) < 1e-12) return 0;

	return ((var)N*sumTP - sumT*sumP) / denom;
}

function stdevReturns(vars R, int N)
{
	if(N < 2) return 0;

	var mean = 0;
	int i;
	for(i=0; i<N; i++) mean += R[i];
	mean /= (var)N;

	var v = 0;
	for(i=0; i<N; i++)
	{
		var d = R[i] - mean;
		v += d*d;
	}
	v /= (var)(N-1);

	return sqrt(max(0, v));
}

function run()
{
	// ------------------------------------------------------------------------
	// SESSION / DATA SETTINGS
	// ------------------------------------------------------------------------
	BarPeriod = 1440;
	StartDate = 20100101;
	EndDate   = 0;

	set(PLOTNOW|RULES|LOGFILE);

	asset("EUR/USD");
	algo("FRACTAL2TF_EUR_RL_v1");

	var eps = 1e-12;
	DataSplit = 50;

	// LookBack must cover the MAX possible TF * MAX window.
	// Max TF is 12, max window here is 220, plus padding.
	LookBack = 3000;

	// ------------------------------------------------------------------------
	// One-time init
	// ------------------------------------------------------------------------
	static int Inited = 0;
	static int PrevOpenTotal = 0;
	static var LastBalance = 0;
	static int Flip = 0; // for forced Train trades

	string LogFN = "Log\\FRACTAL2TF_EUR_RL_v1.csv";

	if(is(FIRSTINITRUN))
	{
		file_delete(LogFN);

		// lite-C safe header (multiple calls)
		file_append(LogFN,"Date,Time,Mode,Bar,");
		file_append(LogFN,"TF1,TF2,TF2d,FDLen1,SlopeLen1,VolLen1,FDLen2,SlopeLen2,VolLen2,");
		file_append(LogFN,"LevScale,MaxLev,PredThr,HoldBars,");
		file_append(LogFN,"FD1,Slope1,Vol1,FD2,Slope2,Vol2,");
		file_append(LogFN,"PredL,PredS,Pred,Lev,Reward\n");

		Inited = 0;
		PrevOpenTotal = 0;
		LastBalance = 0;
		Flip = 0;
	}

	if(!Inited)
	{
		initParNames();
		initParamsRL();
		pickParams();

		LastBalance = Balance;
		PrevOpenTotal = NumOpenTotal;

		Inited = 1;
	}

	// ------------------------------------------------------------------------
	// Convert chosen arms -> parameter values (current episode)
	// ------------------------------------------------------------------------
	int TF1 = (int)armValue(P_TF1, CurArm[P_TF1]);
	int TF2d = (int)armValue(P_TF2D, CurArm[P_TF2D]);
	int TF2 = TF1 + TF2d;
	if(TF2 > 12) TF2 = 12;

	int FDLen1    = (int)armValue(P_FDLEN1,    CurArm[P_FDLEN1]);
	int SlopeLen1 = (int)armValue(P_SLOPELEN1, CurArm[P_SLOPELEN1]);
	int VolLen1   = (int)armValue(P_VOLLEN1,   CurArm[P_VOLLEN1]);

	int FDLen2    = (int)armValue(P_FDLEN2,    CurArm[P_FDLEN2]);
	int SlopeLen2 = (int)armValue(P_SLOPELEN2, CurArm[P_SLOPELEN2]);
	int VolLen2   = (int)armValue(P_VOLLEN2,   CurArm[P_VOLLEN2]);

	var LevScale  = armValue(P_LEVSCALE, CurArm[P_LEVSCALE]);
	var MaxLev    = armValue(P_MAXLEV,   CurArm[P_MAXLEV]);
	var PredThr   = armValue(P_PREDTHR,  CurArm[P_PREDTHR]);
	int HoldBars  = (int)armValue(P_HOLDBARS, CurArm[P_HOLDBARS]);

	// ------------------------------------------------------------------------
	// Build series (2 TF)
	// ------------------------------------------------------------------------
	TimeFrame = TF1;
	vars P1 = series(priceClose());
	vars R1 = series(log(max(eps,P1[0]) / max(eps,P1[1])));

	vars FD1S    = series(0);
	vars Slope1S = series(0);
	vars Vol1S   = series(0);

	TimeFrame = TF2;
	vars P2 = series(priceClose());
	vars R2 = series(log(max(eps,P2[0]) / max(eps,P2[1])));

	vars FD2S    = series(0);
	vars Slope2S = series(0);
	vars Vol2S   = series(0);

	TimeFrame = 1;

	// Warmup gate based on current episode params
	int Need1 = max(max(FDLen1, SlopeLen1), VolLen1) + 5;
	int Need2 = max(max(FDLen2, SlopeLen2), VolLen2) + 5;
	int WarmupBars = max(TF1*Need1, TF2*Need2) + 10;

	if(Bar < WarmupBars)
		return;

	// Do NOT block TRAIN during LOOKBACK
	if(is(LOOKBACK) && !Train)
		return;

	// ------------------------------------------------------------------------
	// Compute features
	// ------------------------------------------------------------------------
	TimeFrame = TF1;
	FD1S[0]    = fractalDimKatz(P1, FDLen1);
	Slope1S[0] = linSlope(P1, SlopeLen1);
	Vol1S[0]   = stdevReturns(R1, VolLen1);

	TimeFrame = TF2;
	FD2S[0]    = fractalDimKatz(P2, FDLen2);
	Slope2S[0] = linSlope(P2, SlopeLen2);
	Vol2S[0]   = stdevReturns(R2, VolLen2);

	TimeFrame = 1;

	// Feature vector for ML
	var Sig[6];
	Sig[0] = FD1S[0];
	Sig[1] = Slope1S[0];
	Sig[2] = Vol1S[0];
	Sig[3] = FD2S[0];
	Sig[4] = Slope2S[0];
	Sig[5] = Vol2S[0];

	// ------------------------------------------------------------------------
	// Trading logic
	// ------------------------------------------------------------------------
	int MethodBase = PERCEPTRON + FUZZY + BALANCED;
	int MethodRet  = MethodBase + RETURNS;

	var PredL=0, PredS=0, Pred=0, Lev=0;

	// time-based exit
	if(NumOpenTotal > 0)
		for(open_trades)
			if(TradeIsOpen && TradeBars >= HoldBars)
				exitTrade(ThisTrade);

	if(Train)
	{
		// Forced alternating trades so ML always gets samples
		if(NumOpenTotal == 0)
		{
			Flip = 1 - Flip;
			LastBalance = Balance; // episode start for reward

			if(Flip)
			{
				adviseLong(MethodRet, 0, Sig, 6);
				Lots = 1; enterLong();
			}
			else
			{
				adviseShort(MethodRet, 0, Sig, 6);
				Lots = 1; enterShort();
			}
		}
	}
	else
	{
		PredL = adviseLong(MethodBase, 0, Sig, 6);
		PredS = adviseShort(MethodBase, 0, Sig, 6);

		// Bootstrap if model has no signal yet
		if(NumOpenTotal == 0 && PredL == 0 && PredS == 0)
		{
			LastBalance = Balance; // episode start for reward
			var s = Sig[1] + Sig[4];
			if(s > 0) { Lots=1; enterLong(); }
			else if(s < 0) { Lots=1; enterShort(); }
			else
			{
				if(random(1) < 0.5) { Lots=1; enterLong(); }
				else                { Lots=1; enterShort(); }
			}
		}
		else
		{
			Pred = PredL - PredS;
			Lev  = clamp(Pred * LevScale, -MaxLev, MaxLev);

			if(Lev > PredThr)       { exitShort(); Lots=1; enterLong();  }
			else if(Lev < -PredThr) { exitLong();  Lots=1; enterShort(); }
			else                    { exitLong();  exitShort(); }
		}
	}

	// ------------------------------------------------------------------------
	// RL reward + update (episode ends when we go from having positions to flat)
	// ------------------------------------------------------------------------
	var Reward = 0;

	if(PrevOpenTotal > 0 && NumOpenTotal == 0)
	{
		Reward = Balance - LastBalance;

		if(Reward != 0)
		{
			int p;
			for(p=0; p<NPAR; p++)
				updateArm(p, CurArm[p], Reward);
		}

		// Next episode parameters
		pickParams();
		LastBalance = Balance;
	}

	PrevOpenTotal = NumOpenTotal;

	// ------------------------------------------------------------------------
	// Logging (one-literal format string)
	// ------------------------------------------------------------------------
	string ModeStr = "Trade";
	if(Train) ModeStr = "Train";
	else if(Test) ModeStr = "Test";

	file_append(LogFN, strf("%04i-%02i-%02i,%02i:%02i,%s,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%.6f,%.3f,%.6f,%d,%.6f,%.8f,%.8f,%.6f,%.8f,%.8f,%.8f,%.8f,%.8f,%.6f,%.6f\n",
		year(0),month(0),day(0), hour(0),minute(0),
		ModeStr, Bar,
		TF1, TF2, TF2d,
		FDLen1, SlopeLen1, VolLen1,
		FDLen2, SlopeLen2, VolLen2,
		LevScale, MaxLev, PredThr, HoldBars,
		Sig[0], Sig[1], Sig[2], Sig[3], Sig[4], Sig[5],
		PredL, PredS, Pred, Lev, Reward
	));

	// ------------------------------------------------------------------------
	// Plots
	// ------------------------------------------------------------------------
	plot("FD_TF1",    Sig[0], NEW, 0);
	plot("FD_TF2",    Sig[3], 0, 0);
	plot("Slope_TF1", Sig[1], 0, 0);
	plot("Slope_TF2", Sig[4], 0, 0);
	plot("Vol_TF1",   Sig[2], 0, 0);
	plot("Vol_TF2",   Sig[5], 0, 0);
	plot("Pred",      Pred, 0, 0);
	plot("Lev",       Lev, 0, 0);
	plot("Reward",    Reward, 0, 0);
}

Page 12 of 12 1 2 10 11 12

Moderated by  Petra 

Powered by UBB.threads™ PHP Forum Software 7.7.1