Strategies
A Strategy script runs on every live price tick with full access to the trade execution API, position management, and sub-indicators calculated in real time.
How Strategies Work
1Init() → Load sub-indicators
2Bar update → proxy.calculate() runs
3Tick() → reads proxy outputs, executes trades
Strategy A — Internal Math
All indicator logic written in proxy .calculate() blocks. Bollinger Bands mean-reversion grid with progressive lot scaling and trailing stop.
PowerScaler.tbcTDSL
about { author: "CoreXTrader"; version: "1.2.0"; }
parameters {
int period = 20; double multiplier = 2.0;
double Lot = 0.01; int MaxEntries = 5;
int TrailStart = 200; int TrailStep = 50;
}
display {
outputs: 3
bb.lower { type: "line"; color: "#50c426ff"; name: "Lower Band"; width: 1; };
bb.upper { type: "line"; color: "#c42626ff"; name: "Upper Band"; width: 1; };
bb.middle { type: "line"; color: "#b0aaaaff"; name: "Middle Band"; width: 0.5; };
fill { buffer_a: 0; buffer_b: 1; color: "rgba(19, 75, 228, 0.66)"; };
fill { buffer_a: 1; buffer_b: 2; color: "rgba(0, 189, 31, 0.72)"; };
}
struct Bands { double upper; double middle; double lower; }
Init() {
Load(bb);
}
bb.calculate() {
double closes[] = close();
int len = candle_count();
int start = Chart.resume_index > 0 ? Chart.resume_index - 1 : period - 1;
series double up[]; series double mid[]; series double lo[];
up[] = create_array(len); mid[] = create_array(len); lo[] = create_array(len);
for (int i = start; i < len; i = i + 1) {
double sum = 0.0;
for (int j = 0; j < period; j = j + 1) { sum = sum + closes[i-j]; }
double mean = sum / period;
mid[i] = mean;
double sq = 0.0;
for (int j = 0; j < period; j = j + 1) { double d = closes[i-j] - mean; sq = sq + (d*d); }
double std_dev = Math.Sqrt(sq / period);
up[i] = mean + (multiplier * std_dev);
lo[i] = mean - (multiplier * std_dev);
}
return Bands { upper: up, middle: mid, lower: lo };
}
int TotalPositions(int side) {
int count = 0;
for (int i = 0; i < Position.Count(); i = i + 1) {
Position.SetIndex(i);
if (Position.Direction() == side) { count = count + 1; }
}
return count;
}
Tick() {
double upper = bb.upper(0); double middle = bb.middle(0); double lower = bb.lower(0);
double bid = Symbol.Bid(); double ask = Symbol.Ask(); string sym = Symbol();
double point = Symbol.Point();
// 1. Progressive lot scaling (0.01, 0.02, 0.03...)
double next_lot_long = Symbol.NormalizeVolume(Lot * (1 + TotalPositions(Side.Long)));
double next_lot_short = Symbol.NormalizeVolume(Lot * (1 + TotalPositions(Side.Short)));
if (ask < lower && TotalPositions(Side.Long) < MaxEntries) { Trade.Buy(sym, next_lot_long); }
if (bid > upper && TotalPositions(Side.Short) < MaxEntries) { Trade.Sell(sym, next_lot_short); }
if (bid > middle && TotalPositions(Side.Long) > 0) { Trade.CloseAll(sym, Side.Long); }
if (ask < middle && TotalPositions(Side.Short) > 0) { Trade.CloseAll(sym, Side.Short); }
// 2. Trailing Stop
for (int i = 0; i < Position.Count(); i = i + 1) {
Position.SetIndex(i);
if (Position.Symbol() == sym) {
int ticket = Position.Ticket();
double sl = Position.SL();
if (Position.Direction() == Side.Long && (bid - Position.OpenPrice()) > TrailStart * point) {
double new_sl = Symbol.NormalizePrice(bid - TrailStep * point);
if (new_sl > sl) {
Trade.Modify(ticket, sym, new_sl, Position.TP());
}
}
if (Position.Direction() == Side.Short && (Position.OpenPrice() - ask) > TrailStart * point) {
double new_sl = Symbol.NormalizePrice(ask + TrailStep * point);
if (new_sl < sl || sl == 0.0) {
Trade.Modify(ticket, sym, new_sl, Position.TP());
}
}
}
}
}Strategy B — Native Engine Indicators
Bind native indicator engines in Init() for maximum performance. RSI + MACD trend-following example.
TrendFilter.tbc — Native RSI + MACDTDSL
parameters {
int rsi_period = 14; double rsi_oversold = 30.0; double rsi_overbought = 70.0;
int macd_fast = 12; int macd_slow = 26; int macd_signal = 9;
double lot = 0.1; int sl_pips = 150; int tp_pips = 300;
}
display {
outputs: 4
NativeRSI.value { type: "line"; color: "#3b82f6"; name: "RSI"; separate_window: true; };
NativeMACD.line { type: "line"; color: "#10b981"; name: "MACD Line"; separate_window: true; };
NativeMACD.signal { type: "line"; color: "#ef4444"; name: "Signal"; };
NativeMACD.histogram { type: "histogram"; color: "#9ca3af"; name: "Histogram"; };
}
struct RSIResult { double value; }
struct MACDResult { double line; double signal; double histogram; }
Init() {
Native.Source(i.RSI); Native.Init(Symbol(), Timeframe);
Native.Parameter(rsi_period, Price.Close); Native.Bind(NativeRSI);
Native.Source(i.MACD); Native.Init(Symbol(), Timeframe);
Native.Parameter(macd_fast, macd_slow, macd_signal, Price.Close); Native.Bind(NativeMACD);
}
NativeRSI.calculate() {
int len = candle_count();
series double rsi_buf[]; rsi_buf[] = create_array(len);
Native.Fetch(0, rsi_buf);
return RSIResult { value: rsi_buf };
}
NativeMACD.calculate() {
int len = candle_count();
series double ml[]; series double ms[]; series double mh[];
ml[] = create_array(len); ms[] = create_array(len); mh[] = create_array(len);
Native.Fetch(0, ml); Native.Fetch(1, ms); Native.Fetch(2, mh);
return MACDResult { line: ml, signal: ms, histogram: mh };
}
Tick() {
double rsi_now = NativeRSI.value(0); double rsi_prev = NativeRSI.value(1);
double hist_now = NativeMACD.histogram(0); double hist_prev = NativeMACD.histogram(1);
string sym = Symbol(); double point = Symbol.Point();
double ask = Symbol.Ask(); double bid = Symbol.Bid();
if (Position.Count() > 0) { return; }
if (rsi_prev < rsi_oversold && rsi_now >= rsi_oversold && hist_prev < 0.0 && hist_now >= 0.0) {
Trade.Buy(sym, lot, Symbol.NormalizePrice(ask - sl_pips*point), Symbol.NormalizePrice(ask + tp_pips*point));
}
if (rsi_prev > rsi_overbought && rsi_now <= rsi_overbought && hist_prev > 0.0 && hist_now <= 0.0) {
Trade.Sell(sym, lot, Symbol.NormalizePrice(bid + sl_pips*point), Symbol.NormalizePrice(bid - tp_pips*point));
}
}Strategy C — Custom External Source
BandRider.tbc — Custom external indicatorTDSL
parameters { int Bands_period = 20; double Bands_mult = 2.0; double lot = 0.1; int sl_pips = 100; int tp_pips = 200; int magic = 77001; }
display {
outputs: 2
Bands.upper { type: "line"; color: "#dc2626"; name: "Upper Band"; };
Bands.lower { type: "line"; color: "#16a34a"; name: "Lower Band"; };
}
struct BandSignal { double upper; double lower; double buy_signal; double sell_signal; }
Init() {
Custom.Source("Bands Arrow.tbc"); Custom.Init(Symbol(), Timeframe);
Custom.Parameter(Bands_period, Bands_mult); Custom.Bind(Bands);
}
Bands.calculate() {
int len = candle_count();
series double up[]; series double lo[]; series double bs[]; series double ss[];
up[] = create_array(len); lo[] = create_array(len);
bs[] = create_array(len); ss[] = create_array(len);
Custom.Fetch(0, up);
Custom.Fetch(1, lo);
Custom.Fetch(2, bs);
Custom.Fetch(3, ss);
return BandSignal { upper: up, lower: lo, buy_signal: bs, sell_signal: ss };
}
Tick() {
double upper = Bands.upper(0); double lower = Bands.lower(0);
double buy_sig = Bands.buy_signal(0); double sell_sig = Bands.sell_signal(0);
double point = Symbol.Point(); string sym = Symbol();
if (buy_sig > 0.0 || sell_sig > 0.0) {
Trade.CancelAll(sym, Side.Long, magic); Trade.CancelAll(sym, Side.Short, magic);
}
if (buy_sig > 0.0) {
double entry = Symbol.NormalizePrice(upper + 2.0 * point);
Trade.BuyStop(sym, lot, entry, entry - sl_pips*point, entry + tp_pips*point, "BandRider Buy", magic);
}
if (sell_sig > 0.0) {
double entry = Symbol.NormalizePrice(lower - 2.0 * point);
Trade.SellStop(sym, lot, entry, entry + sl_pips*point, entry - tp_pips*point, "BandRider Sell", magic);
}
}Strategy D — Hybrid Extension
Fetch data from native engines or external scripts, then perform custom secondary calculations (e.g. Bollinger Bands derived from a Native EMA).
HybridOrchestrator.tbcTDSL
parameters {
int ema_period = 50; double multiplier = 2.0; double lot = 0.1;
}
display {
outputs: 3
MySystem.upper { type: "line"; color: "#dc2626"; name: "Upper (Hybrid)"; };
MySystem.mid { type: "line"; color: "#3b82f6"; name: "EMA Base"; };
MySystem.lower { type: "line"; color: "#16a34a"; name: "Lower (Hybrid)"; };
}
struct HybridResult { double upper; double mid; double lower; }
Init() {
// 1. Bind Native Engine (EMA)
Native.Source(i.EMA); Native.Init(Symbol(), Timeframe);
Native.Parameter(ema_period, Price.Close);
Native.Bind(MySystem);
// 2. Bind Custom External Script (Volatility)
Custom.Source("Keltner Vol.tbc"); Custom.Init(Symbol(), Timeframe);
Custom.Parameter(20, 1.5);
Custom.Bind(MySystem);
}
MySystem.calculate() {
int len = candle_count();
series double ema_buf[]; series double vol_buf[];
series double up[]; series double lo[];
ema_buf[] = create_array(len); vol_buf[] = create_array(len);
up[] = create_array(len); lo[] = create_array(len);
// Fetch from BOTH Native and Custom sources
Native.Fetch(0, ema_buf);
Custom.Fetch(0, vol_buf);
// Combine values for secondary proprietary math
for (int i = Chart.resume_index; i < len; i++) {
up[i] = ema_buf[i] + (multiplier * vol_buf[i]);
lo[i] = ema_buf[i] - (multiplier * vol_buf[i]);
}
return HybridResult { upper: up, mid: ema_buf, lower: lo };
}
Tick() {
if (Symbol.Ask() < MySystem.lower(0)) { Trade.Buy(Symbol(), lot); }
if (Symbol.Bid() > MySystem.upper(0)) { Trade.CloseAll(Symbol(), Side.Long); }
}Advanced Management Patterns
Use these patterns to filter positions by magic number, exclude specific symbols, or implement complex scaling logic using continue; and logic operators.
Filtering & Management HelpersTDSL
// 1. Trailing Stop that excludes a specific symbol
void TrailingExcept(string ignore_sym, int pips) {
double pt = Symbol.Point();
for (int i = 0; i < Position.Count(); i = i + 1) {
Position.SetIndex(i);
if (Position.Symbol() == ignore_sym) { continue; } // Skip this symbol
int tkt = Position.Ticket(); double sl = Position.SL();
if (Position.Direction() == Side.Long && (Symbol.Bid() - Position.OpenPrice()) > pips * pt) {
double nsl = Symbol.NormalizePrice(Symbol.Bid() - (pips/2) * pt);
if (nsl > sl) { Trade.Modify(tkt, Position.Symbol(), nsl, Position.TP()); }
}
}
}
// 2. Close only positions with a specific Magic Number
void CloseByMagic(int target_magic) {
for (int i = Position.Count() - 1; i >= 0; i = i - 1) {
Position.SetIndex(i);
if (Position.Magic() == target_magic) {
Trade.Close(Position.Ticket());
}
}
}
// 3. Count positions excluding a specific Magic Number
int CountExternal(int my_magic) {
int count = 0;
for (int i = 0; i < Position.Count(); i = i + 1) {
Position.SetIndex(i);
if (Position.Magic() != my_magic) { count = count + 1; }
}
return count;
}
// 4. Calculate total profit for a specific Symbol + Magic pair
double GetNetProfit(string sym, int magic) {
double total = 0.0;
for (int i = 0; i < Position.Count(); i = i + 1) {
Position.SetIndex(i);
if (Position.Symbol() == sym && Position.Magic() == magic) {
total = total + Position.Profit();
}
}
return total;
}Utility PatternsTDSL
// Simple New Bar detection
bool is_new_bar() {
static datetime last = 0; datetime cur = time(0);
if (last != cur) { last = cur; return true; } return false;
}
// Check if we are within a trading window
bool is_trade_allowed() {
if (Env.IsBacktest()) { return true; } // Always trade in backtest
return Time.InSession("London") || Time.InSession("NewYork");
}
// Normalized Lot Calculation
double GetRiskLot(double risk_pct, int sl_pips) {
double risk_val = Account.Balance() * (risk_pct / 100.0);
double lot = risk_val / (sl_pips * Symbol.Point() * Symbol.TickValue());
return Symbol.NormalizeVolume(lot);
}