Supported functions

Pine Script functions with a fixed conversion pattern

For the functions below, CodeFlowOS gives the converter a fixed MQL5 and cTrader C# pattern to follow instead of leaving the translation entirely to the AI. This page is built from the same data the converter uses, so it matches what the converter is told.

What a fixed pattern means

  • It means the converter is told which MQL5 and cTrader calls to use for that function.
  • It does not mean the result matches TradingView exactly. Platforms smooth, round and time bars differently. Compare a few bars after converting and backtest on the target platform. See what a platform check does and does not verify.
  • Names such as length or mult stand for the values in your own script. The converter fills them in.
  • The snippets show the pattern for a bot or Expert Advisor. When the source is an indicator, the converter reads values per bar instead (OnCalculate in MQL5, Calculate(index) in cTrader).

At a glance

Pine functionWhat it isStatus
ta.smaSMAFixed pattern
ta.emaEMAFixed pattern
ta.rsiRSIFixed pattern
ta.macdMACDFixed pattern
ta.bbBollinger BandsFixed pattern
ta.bbandsBollinger BandsFixed pattern
ta.atrATRFixed pattern
strategy.closestrategy.closeFixed pattern
ta.crossovercrossoverFixed pattern
ta.crossundercrossunderFixed pattern
request.securitymulti-timeframe requestStarting pattern, needs review
strategy.entrystrategy.entryFixed pattern
strategy.exitstrategy.exitFixed pattern

Indicators

Moving averages, RSI, MACD, Bollinger Bands and ATR. MQL5 indicator functions return a handle, so the pattern creates the handle once and reads values with CopyBuffer.

ta.sma(source, length)

Fixed pattern

MQL5

// OnInit — create handle once
int smaHandle = iMA(_Symbol, _Period, length, 0, MODE_SMA, PRICE_CLOSE);
if(smaHandle == INVALID_HANDLE) return INIT_FAILED;

// OnTick / OnCalculate — never treat iMA() as a double
double smaBuffer[];
ArraySetAsSeries(smaBuffer, true);
if(CopyBuffer(smaHandle, 0, 0, 1, smaBuffer) < 1) return;
double smaValue = smaBuffer[0];

cTrader C#

// OnStart
private SimpleMovingAverage sma;
sma = Indicators.SimpleMovingAverage(Bars.ClosePrices, length);

// OnBar
double smaValue = sma.Result.Last(0);

ta.ema(source, length)

Fixed pattern

MQL5

// OnInit — create handle once
int emaHandle = iMA(_Symbol, _Period, length, 0, MODE_EMA, PRICE_CLOSE);
if(emaHandle == INVALID_HANDLE) return INIT_FAILED;

// OnTick / OnCalculate — never treat iMA() as a double
double emaBuffer[];
ArraySetAsSeries(emaBuffer, true);
CopyBuffer(emaHandle, 0, 0, 1, emaBuffer);
double emaValue = emaBuffer[0];

cTrader C#

// OnStart
private ExponentialMovingAverage ema;
ema = Indicators.ExponentialMovingAverage(Bars.ClosePrices, length);

// OnBar
double emaValue = ema.Result.Last(0);

ta.rsi(source, length)

Fixed pattern — Values can differ slightly from TradingView. Compare a few bars after converting.

MQL5

// OnInit
int rsiHandle = iRSI(_Symbol, _Period, length, PRICE_CLOSE);
if(rsiHandle == INVALID_HANDLE) return INIT_FAILED;

// OnTick / OnCalculate
double rsiBuffer[];
ArraySetAsSeries(rsiBuffer, true);
if(CopyBuffer(rsiHandle, 0, 0, 1, rsiBuffer) < 1) return;
double rsiValue = rsiBuffer[0];

cTrader C#

// OnStart
private RelativeStrengthIndex rsi;
rsi = Indicators.RelativeStrengthIndex(Bars.ClosePrices, length);

// OnBar
double rsiValue = rsi.Result.Last(0);

ta.macd(source, fastlen, slowlen, siglen) → [macd, signal, hist]

Fixed pattern — Values can differ slightly from TradingView. Compare a few bars after converting.

MQL5

// OnInit
int macdHandle = iMACD(_Symbol, _Period, fastlen, slowlen, siglen, PRICE_CLOSE);
if(macdHandle == INVALID_HANDLE) return INIT_FAILED;

// OnTick / OnCalculate — three buffers (MAIN, SIGNAL). Histogram = main - signal
double macdMain[], macdSignal[];
ArraySetAsSeries(macdMain, true);
ArraySetAsSeries(macdSignal, true);
CopyBuffer(macdHandle, 0, 0, 1, macdMain);   // MAIN_LINE
CopyBuffer(macdHandle, 1, 0, 1, macdSignal); // SIGNAL_LINE
double macdValue   = macdMain[0];
double signalValue = macdSignal[0];
double histValue   = macdMain[0] - macdSignal[0];

cTrader C#

// OnStart
// cTrader takes the LONG cycle first, then the short cycle, then the signal period
private MacdCrossOver macd;
macd = Indicators.MacdCrossOver(Bars.ClosePrices, slowlen, fastlen, siglen);

// OnBar
double macdValue   = macd.MACD.Last(0);
double signalValue = macd.Signal.Last(0);
double histValue   = macd.Histogram.Last(0);

ta.bb(source, length, mult) → [middle, upper, lower]

Fixed pattern — Values can differ slightly from TradingView. Compare a few bars after converting.

MQL5

// OnInit
int bbHandle = iBands(_Symbol, _Period, length, 0, mult, PRICE_CLOSE);
if(bbHandle == INVALID_HANDLE) return INIT_FAILED;

// OnTick / OnCalculate — three buffers
double bbMiddle[], bbUpper[], bbLower[];
ArraySetAsSeries(bbMiddle, true);
ArraySetAsSeries(bbUpper, true);
ArraySetAsSeries(bbLower, true);
CopyBuffer(bbHandle, 0, 0, 1, bbMiddle); // BASE_LINE
CopyBuffer(bbHandle, 1, 0, 1, bbUpper);  // UPPER_BAND
CopyBuffer(bbHandle, 2, 0, 1, bbLower);  // LOWER_BAND
double middle = bbMiddle[0];
double upper  = bbUpper[0];
double lower  = bbLower[0];

cTrader C#

// OnStart
private BollingerBands bb;
bb = Indicators.BollingerBands(Bars.ClosePrices, length, mult, MovingAverageType.Simple);

// OnBar
double middle = bb.Main.Last(0);
double upper  = bb.Top.Last(0);
double lower  = bb.Bottom.Last(0);

ta.bbands(source, length, stdev) → [middle, upper, lower]

Fixed pattern — Values can differ slightly from TradingView. Compare a few bars after converting.

MQL5

// Same as ta.bb
int bbHandle = iBands(_Symbol, _Period, length, 0, stdev, PRICE_CLOSE);
double bbMiddle[], bbUpper[], bbLower[];
ArraySetAsSeries(bbMiddle, true);
ArraySetAsSeries(bbUpper, true);
ArraySetAsSeries(bbLower, true);
CopyBuffer(bbHandle, 0, 0, 1, bbMiddle);
CopyBuffer(bbHandle, 1, 0, 1, bbUpper);
CopyBuffer(bbHandle, 2, 0, 1, bbLower);
double middle = bbMiddle[0], upper = bbUpper[0], lower = bbLower[0];

cTrader C#

private BollingerBands bb;
bb = Indicators.BollingerBands(Bars.ClosePrices, length, stdev, MovingAverageType.Simple);
double middle = bb.Main.Last(0), upper = bb.Top.Last(0), lower = bb.Bottom.Last(0);

ta.atr(length)

Fixed pattern — Values can differ slightly from TradingView. Compare a few bars after converting.

MQL5

// OnInit
int atrHandle = iATR(_Symbol, _Period, length);
if(atrHandle == INVALID_HANDLE) return INIT_FAILED;

// OnTick / OnCalculate
double atrBuffer[];
ArraySetAsSeries(atrBuffer, true);
if(CopyBuffer(atrHandle, 0, 0, 1, atrBuffer) < 1) return;
double atrValue = atrBuffer[0];

cTrader C#

// OnStart
private AverageTrueRange atr;
atr = Indicators.AverageTrueRange(length, MovingAverageType.WilderSmoothing);

// OnBar
double atrValue = atr.Result.Last(0);

Crossovers

Signals that fire when one series crosses another.

ta.crossover(source1, source2)

Fixed pattern

MQL5

// MQL5 has no built-in crossover() — check manually using current + previous bar values
bool crossedOver = (prevSource1 <= prevSource2) && (source1 > source2);
// TODO: Manual adjustment needed — ensure prevSource1/prevSource2 are captured
// from the previous OnTick/OnCalculate iteration (store in static/global vars).

cTrader C#

// source1 and source2 are DataSeries, for example fastEma.Result and slowEma.Result
bool crossedOver = source1.HasCrossedAbove(source2, 0);

ta.crossunder(source1, source2)

Fixed pattern

MQL5

// MQL5 has no built-in crossunder() — check manually using current + previous bar values
bool crossedUnder = (prevSource1 >= prevSource2) && (source1 < source2);
// TODO: Manual adjustment needed — ensure prevSource1/prevSource2 are captured
// from the previous OnTick/OnCalculate iteration (store in static/global vars).

cTrader C#

// source1 and source2 are DataSeries, for example fastEma.Result and slowEma.Result
bool crossedUnder = source1.HasCrossedBelow(source2, 0);

Strategy orders

Entering, exiting and closing positions from a Pine strategy.

strategy.close(id, qty_percent=100)

Fixed pattern

MQL5

// Close an open position by symbol (partial close needs volume calc)
if(PositionSelect(_Symbol))
   trade.PositionClose(_Symbol);
// Partial close example (qty_percent < 100):
// double vol = PositionGetDouble(POSITION_VOLUME) * (qtyPercent / 100.0);
// trade.PositionClosePartial(_Symbol, vol);

cTrader C#

var pos = Positions.Find(id);
if(pos != null)
    ClosePosition(pos);

strategy.entry(id, direction, qty=...)

Fixed pattern

MQL5

#include <Trade\Trade.mqh>
CTrade trade;
// long
if(longCondition)
   trade.Buy(lots, _Symbol, 0, sl, tp, "entry-long");
// short
if(shortCondition)
   trade.Sell(lots, _Symbol, 0, sl, tp, "entry-short");

cTrader C#

if(longCondition)
    ExecuteMarketOrder(TradeType.Buy, SymbolName, volume, "entry-long");
if(shortCondition)
    ExecuteMarketOrder(TradeType.Sell, SymbolName, volume, "entry-short");

strategy.exit(id, from_entry, stop=..., limit=..., qty=...)

Fixed pattern

MQL5

// Place/modify SL/TP on an open position, or close it
if(PositionSelect(_Symbol))
  {
   trade.PositionModify(_Symbol, sl, tp);
   // or full close:
   // trade.PositionClose(_Symbol);
  }

cTrader C#

var pos = Positions.Find("entry-long");
if(pos != null)
{
    ModifyPosition(pos, sl, tp);
    // or: ClosePosition(pos);
}

Other timeframes and symbols

Pulling data from another timeframe. This one gives the converter a starting pattern, but it always needs your review.

request.security(symbol, timeframe, expression)

Starting pattern, needs review — Data from another timeframe or symbol needs a separate handle per timeframe. Review it closely.

MQL5

// TODO: Manual adjustment needed for multi-timeframe data.
// Pass an explicit ENUM_TIMEFRAMES for the requested timeframe — NEVER _Period
// (that is the chart's own timeframe, not the higher/lower one being requested).
// Each timeframe needs its OWN handle, created once in OnInit, and its OWN
// CopyBuffer() call — handles/buffers are not shared across timeframes.
int htfMaHandle  = iMA(_Symbol, PERIOD_H1, length, 0, MODE_SMA, PRICE_CLOSE);
int htfRsiHandle = iRSI(_Symbol, PERIOD_H1, length, PRICE_CLOSE);
if(htfMaHandle == INVALID_HANDLE || htfRsiHandle == INVALID_HANDLE) return INIT_FAILED;

double htfMaBuf[], htfRsiBuf[];
ArraySetAsSeries(htfMaBuf, true);
ArraySetAsSeries(htfRsiBuf, true);
if(CopyBuffer(htfMaHandle, 0, 0, 1, htfMaBuf) < 1) return;
if(CopyBuffer(htfRsiHandle, 0, 0, 1, htfRsiBuf) < 1) return;
double htfMaValue  = htfMaBuf[0];
double htfRsiValue = htfRsiBuf[0];

cTrader C#

// TODO: Manual adjustment needed — use MarketData.GetBars(TimeFrame.Hour, SymbolName)
// to pull another timeframe's bars, then index into it as needed.

Everything else

Functions that are not listed here, such as other ta.* functions, input.* calls and drawing or alert functions, are still translated, but without a fixed pattern. The converter writes them itself, so review them. After each Pine Script conversion, the conversion report lists what used a fixed pattern, what the converter wrote on its own, which strategy settings may not carry over, and what is not reproduced exactly, such as drawings and alerts.

Read the Pine Script to MQL5 walkthrough or why results can differ between Pine Script and MQL5. To convert your own script, open the CodeFlowOS converter.