Strategies
Strategies (simulated orders and backtests) are not available in ChartScript yet. Here is what you can build today instead.
A strategy is a script that places simulated orders and reports how they would have performed: entries, exits, position size, profit and drawdown. ChartScript does not have strategies yet. There is no strategy(…) declaration and no strategy.* functions, and ChartScript never places real orders.
A script that tries to use them does not compile:
//@chartscript 1
indicator("Orders are not available")
if (ta.crossover(close, ta.sma(close, 20))) {
strategy.entry("Long", strategy.long)
}When you import a strategy written in another charting script language, ChartDeck converts it into an indicator: its plots, drawings and alert conditions are kept, and the lines that place orders or read strategy results are kept as comments, listed in the import report. See what converts.
#What you can do today
Most of what a strategy shows can be built as an indicator, honestly and on closed bars:
- Entry and exit signals as markers with
plotshape, confirmed on closed bars so they never repaint (see repainting). - Stops and targets as lines that follow an open "position" you track yourself in
statevariables. - A results table on the last bar: number of signals, how many reached the target first, average move after a signal.
- Alert conditions with
alert.on, which you can turn into script alerts that ChartDeck checks on its servers.
Keep in mind what such a table is not: it has no fees, no funding, no slippage and no position sizing, so treat it as a quick look at a signal, not as a test of a trading system.
#A whole example: signals with a tracked target and stop
This indicator enters a hypothetical long on a confirmed close above the 20-bar high, then follows it until price reaches a target or a stop (both multiples of the ATR at entry). It draws the levels while a signal is open and counts the outcomes in a small table.
//@chartscript 1
indicator("Breakout signal tracker", { overlay: true })
const len = input.int(20, "Breakout length", { minval: 2 })
const tgtMult = input.float(2.0, "Target (x ATR)", { minval: 0.1, step: 0.1 })
const stopMult = input.float(1.0, "Stop (x ATR)", { minval: 0.1, step: 0.1 })
const atr = ta.atr(14)
const signal = close > ta.highest(high, len)[1] && barstate.isconfirmed
state target: float = na
state stop: float = na
state wins: int = 0
state losses: int = 0
const inTrade = !na(target)
if (inTrade && barstate.isconfirmed) {
if (high >= target) {
wins += 1
target = na
stop = na
} else if (low <= stop) {
losses += 1
target = na
stop = na
}
}
const startNew = signal && na(target)
if (startNew) {
target = close + tgtMult * atr
stop = close - stopMult * atr
}
plotshape(startNew, "Signal", shape.triangleup, location.belowbar, color.up)
plot(target, "Target", color.up, { style: plot.style_linebr })
plot(stop, "Stop", color.down, { style: plot.style_linebr })
state t: table = table.new(position.top_right, 2, 3)
if (barstate.islast) {
const total = wins + losses
table.cell(t, 0, 0, "Target first", { text_color: color.text })
table.cell(t, 1, 0, str.tostring(wins), { text_color: color.up })
table.cell(t, 0, 1, "Stop first", { text_color: color.text })
table.cell(t, 1, 1, str.tostring(losses), { text_color: color.down })
table.cell(t, 0, 2, "Hit rate", { text_color: color.text })
table.cell(t, 1, 2, total > 0 ? str.tostring(wins / total * 100, "0") + "%" : "-", { text_color: color.text })
}When a bar reaches both the target and the stop, the script counts the target first; with one bar it cannot know which came first. That is one more reason to read the table as a sketch.