Export backtest strategies to indicator/strategy code for major trading platforms — TradingView, 通达信, 同花顺, 东方财富, MT5.
57
66%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Fix and improve this skill with Tessl
tessl review fix ./agent/src/skills/pine-script/SKILL.mdThis skill exports a Vibe-Trading strategy to all major trading platforms in one go.
Output file: artifacts/strategy.pine (inside the run directory).
Supported platforms (always generate ALL):
| Group | Platforms | Language |
|---|---|---|
| International Charts | TradingView | Pine Script v6 |
| China Equities | 通达信 / 同花顺 / 东方财富 | TDX Formula |
| Forex / CFD | MetaTrader 5 | MQL5 |
load_skill("pine-script") — read this guideread_file("config.json") — understand instruments, dates, parametersread_file("code/signal_engine.py") — understand the Python strategy logicwrite_file("artifacts/strategy.pine") — save the combined outputload_skill("pine-script") — read this guidewrite_file("artifacts/strategy.pine") — save the combined outputThe output file uses this structure (all platforms in one file):
================================================================================
TRADINGVIEW — Pine Script v6
Paste into: Pine Editor → New blank indicator → Add to Chart
================================================================================
[Pine Script code here]
================================================================================
通达信 / 同花顺 / 东方财富 (TDX Formula)
Paste into: 功能 → 公式管理器 → 新建指标公式
================================================================================
[TDX formula code here]
================================================================================
MT5 — MQL5
Save as: .mq5 file → MetaEditor → Compile → Navigator → Attach to Chart
================================================================================
[MQL5 code here]// This strategy was generated by Vibe-Trading
// Paste into TradingView Pine Editor → Add to Chart
//@version=6
strategy("Strategy Name", overlay=true, default_qty_type=strategy.percent_of_equity, default_qty_value=100, commission_type=strategy.commission.percent, commission_value=0.1, initial_capital=1000000)
// ============================================================================
// INPUTS
// ============================================================================
// [Group inputs logically with input.int(), input.float(), input.string()]
// ============================================================================
// CALCULATIONS
// ============================================================================
// [Core indicator calculations]
// ============================================================================
// CONDITIONS
// ============================================================================
longCondition = false
shortCondition = false
exitLongCondition = false
exitShortCondition = false
// ============================================================================
// STRATEGY EXECUTION
// ============================================================================
if longCondition
strategy.entry("Long", strategy.long)
if shortCondition
strategy.entry("Short", strategy.short)
if exitLongCondition
strategy.close("Long")
if exitShortCondition
strategy.close("Short")
// ============================================================================
// PLOTS
// ============================================================================
// [Visual overlays: moving averages, bands, signals]
// ============================================================================
// ALERTS
// ============================================================================
alertcondition(longCondition, title="Long Signal", message="Long entry signal triggered")
alertcondition(shortCondition, title="Short Signal", message="Short entry signal triggered")| Python (pandas/numpy) | Pine Script v6 |
|---|---|
df['close'].rolling(n).mean() | ta.sma(close, n) |
df['close'].ewm(span=n).mean() | ta.ema(close, n) |
ta.RSI(df['close'], n) or manual RSI | ta.rsi(close, n) |
ta.MACD(df['close']) | [macdLine, signalLine, hist] = ta.macd(close, 12, 26, 9) |
df['close'].rolling(n).std() | ta.stdev(close, n) |
df['high'].rolling(n).max() | ta.highest(high, n) |
df['low'].rolling(n).min() | ta.lowest(low, n) |
df['close'].pct_change(fill_method=None) | (close - close[1]) / close[1] |
df['volume'].rolling(n).mean() | ta.sma(volume, n) |
df['close'] > df['close'].shift(1) | close > close[1] |
| Bollinger Bands | [mid, upper, lower] = ta.bb(close, length, mult) |
| ATR | ta.atr(length) |
| ADX | ta.adx(high, low, close, length) |
| Stochastic | ta.stoch(close, high, low, length, smoothK, smoothD) |
| CCI | ta.cci(close, length) |
| Williams %R | ta.wpr(length) |
| MFI | ta.mfi(close, length) |
| OBV | ta.obv |
| VWAP | ta.vwap |
| Python | Pine Script v6 |
|---|---|
df['open'] | open |
df['high'] | high |
df['low'] | low |
df['close'] | close |
df['volume'] | volume |
df.index (datetime) | time |
df['close'].shift(n) | close[n] |
| Python Pattern | Pine Script v6 |
|---|---|
(fast > slow) & (fast.shift(1) <= slow.shift(1)) | ta.crossover(fast, slow) |
(fast < slow) & (fast.shift(1) >= slow.shift(1)) | ta.crossunder(fast, slow) |
signal.where(condition, 0) | condition ? value : 0 |
np.where(cond, val_true, val_false) | cond ? val_true : val_false |
signal.clip(-1, 1) | math.max(-1, math.min(1, signal)) |
signal.fillna(0) | nz(signal, 0) |
pd.isna(value) | na(value) |
| Python Pattern | Pine Script v6 |
|---|---|
| Equal weight 1/N | strategy.percent_of_equity with default_qty_value = 100/N |
| Full position on signal=1.0 | default_qty_type=strategy.percent_of_equity, default_qty_value=100 |
| Half position on signal=0.5 | Use strategy.entry(..., qty=strategy.equity * 0.5 / close) |
| Stop-loss | strategy.exit("Exit", stop=entryPrice * (1 - stopPct)) |
| Take-profit | strategy.exit("Exit", limit=entryPrice * (1 + tpPct)) |
//@version=6text = condition ? "a" : "b"plot(condition ? value : na)barstate.isconfirmed, lookahead=barmerge.lookahead_offThese platforms share 95%+ identical formula syntax. Write ONE version that works on all three.
{Vibe-Trading 策略导出}
{策略名称: XXX}
{——————— 参数 ———————}
N:=14;
M:=6;
{——————— 指标计算 ———————}
RSI_VAL:=RSI(CLOSE,N);
MA_FAST:=MA(CLOSE,5);
MA_SLOW:=MA(CLOSE,20);
{——————— 买卖信号 ———————}
BUY:CROSS(MA_FAST,MA_SLOW) AND RSI_VAL<40,COLORRED;
SELL:CROSS(MA_SLOW,MA_FAST) AND RSI_VAL>60,COLORGREEN;
DRAWTEXT(BUY,LOW,'B'),COLORYELLOW;
DRAWTEXT(SELL,HIGH,'S'),COLORWHITE;| Python | TDX Formula |
|---|---|
df['close'].rolling(n).mean() | MA(CLOSE,N) |
df['close'].ewm(span=n).mean() | EMA(CLOSE,N) |
| RSI | RSI(CLOSE,N) (returns 0-100) |
| MACD | MACD.DIF, MACD.DEA, MACD.MACD or manual: DIF:=EMA(CLOSE,12)-EMA(CLOSE,26); DEA:=EMA(DIF,9); MACD:=(DIF-DEA)*2; |
| Bollinger Bands | BOLL(N,M) → BOLL.UPPER, BOLL.MID, BOLL.LOWER or manual |
| ATR | ATR:=MA(MAX(MAX(HIGH-LOW,ABS(HIGH-REF(CLOSE,1))),ABS(LOW-REF(CLOSE,1))),N); |
df['close'].shift(n) | REF(CLOSE,N) |
df['high'].rolling(n).max() | HHV(HIGH,N) |
df['low'].rolling(n).min() | LLV(LOW,N) |
| crossover(fast, slow) | CROSS(FAST,SLOW) |
| crossunder(fast, slow) | CROSS(SLOW,FAST) |
df['volume'] | VOL |
abs(x) | ABS(X) |
max(a,b) | MAX(A,B) |
min(a,b) | MIN(A,B) |
| conditional | IF(COND,A,B) |
df['close'].pct_change(fill_method=None) | (CLOSE-REF(CLOSE,1))/REF(CLOSE,1) |
| count true in N bars | COUNT(COND,N) |
| sum over N bars | SUM(X,N) |
| std over N bars | STD(CLOSE,N) |
| slope / linear regression | SLOPE(CLOSE,N) |
:= for intermediate variables, : for output (plotted) lines{comment} — curly braces, NOT //;COLORRED, COLORGREEN, COLORYELLOW, COLORWHITE, COLORBLUE, COLORCYAN, COLORMAGENTALINETHICK2, POINTDOT, STICK, VOLSTICKDRAWTEXT(COND, PRICE, 'TEXT'), COLOR;DRAWICON(COND, PRICE, ICON_ID);| Feature | 通达信 | 同花顺 | 东方财富 |
|---|---|---|---|
| MACD built-in | MACD(12,26,9) | MACD(12,26,9) | same |
| Stochastic | KDJ(N,M1,M2) | same | same |
| Custom color | COLOR+RRGGBB | COLOR+RRGGBB | limited |
| Strategy backtest | 条件选股 only | 条件选股 only | 条件选股 only |
For maximum compatibility, avoid platform-specific extensions. Stick to core functions.
//+------------------------------------------------------------------+
//| Generated by Vibe-Trading |
//+------------------------------------------------------------------+
#property copyright "Vibe-Trading"
#property indicator_chart_window // or indicator_separate_window
#property indicator_buffers 2
#property indicator_plots 2
#property indicator_color1 clrDodgerBlue
#property indicator_color2 clrRed
input int InpPeriod = 14; // Period
double BuyBuffer[];
double SellBuffer[];
int OnInit()
{
SetIndexBuffer(0, BuyBuffer, INDICATOR_DATA);
SetIndexBuffer(1, SellBuffer, INDICATOR_DATA);
PlotIndexSetInteger(0, PLOT_ARROW, 233); // up arrow
PlotIndexSetInteger(1, PLOT_ARROW, 234); // down arrow
PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_ARROW);
PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_ARROW);
return(INIT_SUCCEEDED);
}
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
int start = MathMax(prev_calculated - 1, InpPeriod);
for(int i = start; i < rates_total; i++)
{
BuyBuffer[i] = EMPTY_VALUE;
SellBuffer[i] = EMPTY_VALUE;
// === YOUR LOGIC HERE ===
// Example: if(buyCondition) BuyBuffer[i] = low[i];
// if(sellCondition) SellBuffer[i] = high[i];
}
return(rates_total);
}| Python | MQL5 |
|---|---|
df['close'].rolling(n).mean() | iMA(_Symbol, PERIOD_CURRENT, n, 0, MODE_SMA, PRICE_CLOSE) or manual loop |
| EMA | iMA(..., MODE_EMA, ...) |
| RSI | iRSI(_Symbol, PERIOD_CURRENT, n, PRICE_CLOSE) |
| MACD | iMACD(_Symbol, PERIOD_CURRENT, 12, 26, 9, PRICE_CLOSE) |
| Bollinger | iBands(_Symbol, PERIOD_CURRENT, n, 0, mult, PRICE_CLOSE) |
| ATR | iATR(_Symbol, PERIOD_CURRENT, n) |
| Stochastic | iStochastic(_Symbol, PERIOD_CURRENT, K, D, slowing, MODE_SMA, STO_LOWHIGH) |
df['close'].shift(n) | close[i-n] (in OnCalculate loop) |
| crossover | buf[i] > ref[i] && buf[i-1] <= ref[i-1] |
iMA() etc. in OnInit(), use CopyBuffer() to get valuesArraySetAsSeries() to reverse.mq5), not Expert Advisor, to match "indicator export" purposeOnInit, read in OnCalculateWhen generating code, map Vibe-Trading instrument codes appropriately:
| Vibe-Trading | TradingView | 通达信/同花顺 | MT5 |
|---|---|---|---|
000001.SZ | SZSE:000001 | 000001 | N/A |
600519.SH | SSE:600519 | 600519 | N/A |
AAPL.US | NASDAQ:AAPL | N/A | AAPL |
BTC-USDT | BINANCE:BTCUSDT | N/A | BTCUSD |
Note: Most indicator code is instrument-agnostic — the user applies it to whatever chart they're viewing. Include a comment noting the original instrument for reference only.
When a Python strategy uses features that can't be directly translated, clearly note it:
| Python Feature | Platform Limitation |
|---|---|
| ML models (sklearn, etc.) | None — flag as "manual implementation required" |
| Custom pandas operations | TDX — limited to built-in functions |
| Multi-timeframe logic | TDX — no native MTF; Pine/MQL5 — supported |
| Dynamic position sizing | TDX — indicator only, no position control |
| External data (API calls) | All — indicators run offline on chart data only |
Always add a comment block at the top listing any features that could not be translated.
Before outputting:
//@version=6 is first line, no plot() in local scope, ternary on single lines:= for intermediate, : for output, {comments}EMPTY_VALUE for no-signalf9cb061
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.