---
name: pine-script
description: Export backtest strategies to indicator/strategy code for major trading platforms — TradingView, 通达信, 同花顺, 东方财富, MT5.
category: tool
---

## Overview

This 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 |

## Workflow: Export from Backtest

1. `load_skill("pine-script")` — read this guide
2. `read_file("config.json")` — understand instruments, dates, parameters
3. `read_file("code/signal_engine.py")` — understand the Python strategy logic
4. **Translate** the strategy to ALL platforms using the references below
5. `write_file("artifacts/strategy.pine")` — save the combined output
6. Return the code in a code block with usage instructions per platform

## Workflow: Generate from Description

1. `load_skill("pine-script")` — read this guide
2. Write indicator/strategy code for ALL platforms based on the user's description
3. `write_file("artifacts/strategy.pine")` — save the combined output
4. Return the code with usage instructions

## Output Format

The 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]

```

---

# Platform Reference

## 1. TradingView — Pine Script v6

### Template

```pinescript
// 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 → Pine Script Mapping

| 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()` | `(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` |

### Data References

| 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]` |

### Signal Logic

| 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)` |

### Position Sizing

| 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))` |

### Syntax Rules (Critical)

1. **Version declaration must be first line**: `//@version=6`
2. **Ternary operators MUST stay on one line**: `text = condition ? "a" : "b"`
3. **Line continuation**: continuation lines must be indented MORE than the starting line
4. **No plot() in local scope** (if/for/function) — use `plot(condition ? value : na)`
5. **var**: persistent state across bars; regular assignment recalculates each bar
6. **Avoid repainting**: use `barstate.isconfirmed`, `lookahead=barmerge.lookahead_off`
7. **Limits**: max 500 bars lookback, 500 plot calls, 64 entry/exit per bar, 40 request.security()

---

## 2. 通达信 / 同花顺 / 东方财富 — TDX Formula

These platforms share 95%+ identical formula syntax. Write ONE version that works on all three.

### Template

```
{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 Mapping

| 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()` | `(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)` |

### Syntax Rules

1. **Assignment**: `:=` for intermediate variables, `:` for output (plotted) lines
2. **Comments**: `{comment}` — curly braces, NOT `//`
3. **No semicolons optional**: each statement ends with `;`
4. **Colors**: `COLORRED`, `COLORGREEN`, `COLORYELLOW`, `COLORWHITE`, `COLORBLUE`, `COLORCYAN`, `COLORMAGENTA`
5. **Line styles**: `LINETHICK2`, `POINTDOT`, `STICK`, `VOLSTICK`
6. **Draw text**: `DRAWTEXT(COND, PRICE, 'TEXT'), COLOR;`
7. **Draw icon**: `DRAWICON(COND, PRICE, ICON_ID);`
8. **All function/variable names UPPERCASE**
9. **No loops / no arrays** — everything is vectorized bar-by-bar
10. **Max formula length**: ~10,000 characters per formula

### Platform Differences

| 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.

---

## 3. MetaTrader 5 — MQL5

### Template (Custom Indicator)

```mql5
//+------------------------------------------------------------------+
//| 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 Mapping

| 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]` |

### Syntax Rules

1. **Indicator handles**: call `iMA()` etc. in `OnInit()`, use `CopyBuffer()` to get values
2. **Buffer direction**: MQL5 buffers are indexed 0=oldest by default; use `ArraySetAsSeries()` to reverse
3. **EMPTY_VALUE**: use for "no signal" on arrow plots
4. **Indicator vs EA**: generate indicator (`.mq5`), not Expert Advisor, to match "indicator export" purpose
5. **Handle-based API**: MQL5 uses handles — create in `OnInit`, read in `OnCalculate`

---

## Symbol Format Mapping

When 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.

## Limitations & Transparency

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.

## Quality Checklist

Before outputting:
- [ ] ALL 3 platform sections are included (Pine Script, TDX, MQL5)
- [ ] Each platform section has proper header with usage instructions
- [ ] Pine Script: `//@version=6` is first line, no plot() in local scope, ternary on single lines
- [ ] TDX: all uppercase functions, `:=` for intermediate, `:` for output, `{comments}`
- [ ] MQL5: proper handle-based API, `EMPTY_VALUE` for no-signal
- [ ] Entry/exit conditions match the Python signal logic semantically across ALL platforms
- [ ] Untranslatable features are clearly documented at the top of each section
- [ ] Comment header notes the original Vibe-Trading run_id and instrument
