PowerLanguage 常用語法大全:從入門到實戰

PowerLanguage 是 MultiCharts 內建的程式語言,用來寫交易策略、自訂指標和訊號。它的語法跟 TradeStation 的 EasyLanguage 幾乎一樣,學會一種等於兩邊都能用。

這篇文章把 PowerLanguage 最常用的語法整理成一份參考手冊。從變數宣告、條件判斷到實際的策略程式碼範例,每個語法都附上可以直接貼進 PowerLanguage Editor 跑的程式碼。

基本架構:一支策略長什麼樣子

先看一支最簡單的策略,讓你有個整體概念:

// 雙均線交叉策略 - 最基本的範例
Inputs: FastLen(5), SlowLen(20);
Variables: FastMA(0), SlowMA(0);

FastMA = Average(Close, FastLen);
SlowMA = Average(Close, SlowLen);

If FastMA Crosses Over SlowMA Then
    Buy next bar at market;

If FastMA Crosses Under SlowMA Then
    SellShort next bar at market;

這 10 行程式碼做了三件事:定義參數、計算指標、根據條件下單。PowerLanguage 的所有策略都遵循這個結構。

變數類型:Inputs、Variables、Arrays

Inputs(輸入參數)

Inputs 用來定義策略的可調參數。回測時你可以在 MultiCharts 的設定面板直接修改這些數值,不用改程式碼。

// 基本語法
Inputs: ParamName(DefaultValue);

// 實際範例
Inputs: Length(20);              // 整數參數
Inputs: StopLoss(0.02);         // 浮點數參數
Inputs: UseTrailingStop(true);  // 布林值參數
Inputs: StartTime(0930);        // 時間參數

// 一次宣告多個
Inputs: FastLen(5), SlowLen(20), RiskPct(0.02);

Inputs 的好處是可以用 MultiCharts 的「最佳化」功能,自動掃描不同參數組合的回測績效。例如讓 FastLen 從 3 跑到 20、SlowLen 從 10 跑到 60,找出最佳組合。

Variables(變數)

Variables 用來儲存計算過程中的中間值。每根 K 棒都會重新執行一次策略程式碼,Variables 的值會保留到下一根 K 棒。

// 基本語法
Variables: VarName(InitialValue);

// 實際範例
Variables: MyMA(0);             // 數值變數,初始值 0
Variables: Signal("");          // 字串變數,初始值空字串
Variables: IsLong(false);       // 布林變數,初始值 false
Variables: EntryPrice(0), ExitPrice(0);  // 多個變數

// intrabarpersist - 在即時 K 棒的每個 tick 都保留值
Variables: intrabarpersist TickCount(0);

重點:一般 Variables 在即時盤中,每個 tick 進來時會被重設為上一根收盤 K 棒的值。如果你需要在即時 tick 之間保留值(例如計算當根 K 棒內的 tick 數),要加上 intrabarpersist 關鍵字。

Arrays(陣列)

Arrays 用來儲存一系列的值,適合需要回顧多根 K 棒資料的情境。

// 基本語法
Arrays: ArrayName[Size](InitialValue);

// 實際範例
Arrays: PriceBuffer[50](0);         // 50 個元素的數值陣列
Arrays: SignalLog[100]("");          // 100 個元素的字串陣列

// 存取陣列元素(索引從 0 開始)
PriceBuffer[0] = Close;
PriceBuffer[1] = Close[1];

// 二維陣列
Arrays: Matrix[10, 5](0);
Matrix[2, 3] = 100;

資料存取:取得價格和成交量

PowerLanguage 有一組內建的保留字,讓你直接取得 K 棒資料。

當根 K 棒資料

// 價格資料
Open      // 開盤價
High      // 最高價
Low       // 最低價
Close     // 收盤價(即時盤中 = 最新成交價)
Volume    // 成交量
Ticks     // tick 數

// 時間資料
Date      // 日期(格式:1260401 = 2026/04/01)
Time      // 時間(格式:1430 = 14:30)
DateTime  // 日期時間的序列值
BarNumber // 目前是第幾根 K 棒

歷史 K 棒資料(往回看)

在任何資料後面加上方括號和數字,就能取得前幾根 K 棒的值。這是寫策略最常用的技巧之一。

Close[0]   // 當根 K 棒的收盤價(和 Close 一樣)
Close[1]   // 前 1 根 K 棒的收盤價
Close[2]   // 前 2 根 K 棒的收盤價
High[5]    // 前 5 根 K 棒的最高價
Volume[1]  // 前 1 根 K 棒的成交量

例如「今天收盤價比昨天高」這個條件可以寫成:

If Close > Close[1] Then
    // 做某件事 ;

多資料源

如果你的圖表上掛了多個資料源(Data1、Data2…),可以用 of Data(N) 來指定。

// Data1 = 台指期, Data2 = 電子期
Value1 = Close of Data(1);    // 台指期收盤價
Value2 = Close of Data(2);    // 電子期收盤價
Value3 = Volume of Data(2);   // 電子期成交量

條件判斷:If-Then-Else 和 Switch-Case

If-Then 基本用法

// 單行
If Close > Open Then Buy next bar at market;

// 多行(用 Begin...End 括起來)
If Close > Open Then Begin
    Buy next bar at market;
    Print("買進訊號觸發");
End;

// If-Then-Else
If Close > Average(Close, 20) Then
    Buy next bar at market
Else
    SellShort next bar at market;

// 巢狀 If
If Close > Open Then Begin
    If Volume > Volume[1] Then
        Buy ("量增紅K") next bar at market;
End;

複合條件

// AND - 所有條件都要成立
If Close > Open AND Volume > 1000 Then
    Buy next bar at market;

// OR - 其中一個條件成立就好
If RSI(Close, 14) > 70 OR RSI(Close, 14) < 30 Then
    Print("RSI 進入極端區域");

// NOT - 反轉條件
If NOT (MarketPosition = 1) Then
    Print("目前沒有多單部位");

// 混合使用(用括號釐清優先順序)
If (Close > Open AND Volume > Volume[1]) OR
   (Close > Highest(High, 20)[1]) Then
    Buy next bar at market;

比較運算子

運算子 意義 範例
=等於If MarketPosition = 1 Then
<>不等於If MarketPosition <> 0 Then
>大於If Close > Open Then
<小於If Close < Open Then
>=大於等於If Volume >= 5000 Then
<=小於等於If Low <= Low[1] Then

Switch-Case

當你要根據一個變數的不同值做不同的事情時,Switch-Case 比一堆 If-Else 更乾淨。

Variables: DayType(0);
DayType = DayOfWeek(Date);

Switch (DayType)
Begin
    Case 1:  // 星期一
        Print("週一,觀望為主");
    Case 2:  // 星期二
        Print("週二,留意結算行情");
    Case 5:  // 星期五
        Print("週五,注意尾盤拉高倒貨");
    Default:
        Print("一般交易日");
End;

迴圈結構:For 和 While

For 迴圈

// 計算最近 10 根 K 棒的平均成交量
Variables: SumVol(0), AvgVol(0);
SumVol = 0;

For Value1 = 0 To 9 Begin
    SumVol = SumVol + Volume[Value1];
End;

AvgVol = SumVol / 10;

// 找出最近 20 根 K 棒中最大的實體 K 棒(收盤-開盤的絕對值)
Variables: MaxBody(0), MaxBodyBar(0);
MaxBody = 0;

For Value1 = 0 To 19 Begin
    If AbsValue(Close[Value1] - Open[Value1]) > MaxBody Then Begin
        MaxBody = AbsValue(Close[Value1] - Open[Value1]);
        MaxBodyBar = Value1;
    End;
End;

While 迴圈

// 從當根 K 棒往回找,找到第一根成交量超過 10000 的 K 棒
Variables: LookBack(0);
LookBack = 0;

While LookBack < 100 AND Volume[LookBack] <= 10000 Begin
    LookBack = LookBack + 1;
End;

If LookBack < 100 Then
    Print("前 ", NumToStr(LookBack, 0), " 根 K 棒有大量");

注意:While 迴圈一定要有終止條件,不然程式會卡在無限迴圈。上面的範例用 LookBack < 100 當安全閥,最多只往回找 100 根。

內建函數:你不用重新造輪子

PowerLanguage 內建了上百個函數,以下是最常用的幾類。

移動平均線類

Average(Close, 20)              // 簡單移動平均(SMA)
XAverage(Close, 20)             // 指數移動平均(EMA)
WAverage(Close, 20)             // 加權移動平均(WMA)
AdaptiveMovAvg(Close, 20)       // 自適應移動平均(AMA)

極值類

Highest(High, 20)       // 最近 20 根 K 棒的最高價
Lowest(Low, 20)         // 最近 20 根 K 棒的最低價
HighestBar(High, 20)    // 最高價出現在幾根 K 棒之前
LowestBar(Low, 20)      // 最低價出現在幾根 K 棒之前

交叉判斷類

// CrossOver - A 從下往上穿越 B
If Average(Close, 5) Crosses Over Average(Close, 20) Then
    Buy next bar at market;

// CrossUnder - A 從上往下穿越 B
If Average(Close, 5) Crosses Under Average(Close, 20) Then
    SellShort next bar at market;

// 也可以寫成函數形式
If CrossOver(Average(Close, 5), Average(Close, 20)) Then
    Buy next bar at market;

數學函數

AbsValue(-50)          // 絕對值 → 50
MaxList(10, 20, 30)    // 取最大值 → 30
MinList(10, 20, 30)    // 取最小值 → 10
Square(5)              // 平方 → 25
SquareRoot(25)         // 平方根 → 5
Power(2, 10)           // 2 的 10 次方 → 1024
Log(100)               // 自然對數
ExpValue(1)            // e 的次方
Mod(10, 3)             // 取餘數 → 1
Round(3.7, 0)          // 四捨五入 → 4
IntPortion(3.7)        // 取整數部分 → 3
FracPortion(3.7)       // 取小數部分 → 0.7

標準差與統計

StandardDev(Close, 20, 1)   // 收盤價 20 期標準差
Summation(Close, 20)         // 最近 20 根收盤價加總
NumericSeriesCompress(Close, 5)  // 資料壓縮

下單函數:Buy、Sell、SellShort、BuyToCover

PowerLanguage 有四個下單指令,對應多空的進場和出場。

函數 動作 用途
Buy買進建立多單做多進場
Sell賣出平掉多單做多出場
SellShort放空建立空單做空進場
BuyToCover回補平掉空單做空出場

市價單(Market Order)

Buy next bar at market;
Sell next bar at market;
SellShort next bar at market;
BuyToCover next bar at market;

// 帶名稱(方便在報表裡辨識)
Buy ("MA交叉多") next bar at market;
Sell ("停損出場") next bar at market;

限價單(Limit Order)

// 在指定價格買進(掛限價單)
Buy next bar at 18000 Limit;

// 在開盤價下方 50 點掛買進限價單
Buy next bar at Open - 50 Limit;

停損單(Stop Order)

// 價格突破 18500 就買進
Buy next bar at 18500 Stop;

// 跌破前根 K 棒低點就放空
SellShort next bar at Low[1] Stop;

指定下單口數

// 買進 2 口
Buy 2 contracts next bar at market;

// 根據帳戶資金動態計算口數
Variables: Lots(0);
Lots = IntPortion(10000 / (Close * BigPointValue * 0.1));
If Lots >= 1 Then
    Buy Lots contracts next bar at market;

內建停利停損

// 固定點數停損(以台指期為例,1 點 = 200 元)
SetStopLoss(10000);          // 虧損 10,000 元就停損

// 固定點數停利
SetProfitTarget(20000);      // 獲利 20,000 元就停利

// 追蹤停損(Trail Stop)
SetPercentTrailing(2);       // 從最高獲利回撤 2% 就出場

// 自訂點數追蹤停損
SetDollarTrailing(8000);     // 從最高獲利回撤 8,000 元就出場

// N 根 K 棒後強制出場
SetExitOnClose;              // 收盤出場(當沖用)

部位資訊:MarketPosition 和 EntryPrice

MarketPosition     // 目前部位方向:1=多單, -1=空單, 0=空手
CurrentContracts   // 目前持有口數
EntryPrice         // 進場價格
EntryDate          // 進場日期
EntryTime          // 進場時間
BarsSinceEntry     // 進場後經過幾根 K 棒

// 範例:持倉超過 10 根 K 棒就出場
If MarketPosition = 1 AND BarsSinceEntry >= 10 Then
    Sell ("時間出場") next bar at market;

// 範例:獲利超過 100 點就停利
If MarketPosition = 1 AND Close - EntryPrice >= 100 Then
    Sell ("停利100點") next bar at market;

常見指標實作範例

直接上程式碼,你可以貼到 PowerLanguage Editor 裡試。

均線交叉策略(MA Crossover)

// ====== 均線交叉策略 ======
Inputs: FastLen(5), SlowLen(20);
Variables: FastMA(0), SlowMA(0);

FastMA = Average(Close, FastLen);
SlowMA = Average(Close, SlowLen);

// 進場
If FastMA Crosses Over SlowMA Then
    Buy ("黃金交叉") next bar at market;

If FastMA Crosses Under SlowMA Then
    SellShort ("死亡交叉") next bar at market;

// 停損
SetStopLoss(10000);

RSI 超買超賣策略

// ====== RSI 策略 ======
Inputs: RSILen(14), OverBought(70), OverSold(30);
Variables: MyRSI(0);

MyRSI = RSI(Close, RSILen);

// RSI 從超賣區回升 → 買進
If MyRSI Crosses Over OverSold Then
    Buy ("RSI回升") next bar at market;

// RSI 從超買區回落 → 放空
If MyRSI Crosses Under OverBought Then
    SellShort ("RSI回落") next bar at market;

// 反向訊號出場
If MarketPosition = 1 AND MyRSI > OverBought Then
    Sell ("RSI過熱") next bar at market;

If MarketPosition = -1 AND MyRSI < OverSold Then
    BuyToCover ("RSI過冷") next bar at market;

MACD 策略

// ====== MACD 策略 ======
Inputs: FastEMA(12), SlowEMA(26), SignalLen(9);
Variables: MACDLine(0), SignalLine(0), Histogram(0);

MACDLine = XAverage(Close, FastEMA) - XAverage(Close, SlowEMA);
SignalLine = XAverage(MACDLine, SignalLen);
Histogram = MACDLine - SignalLine;

// MACD 線穿越訊號線
If MACDLine Crosses Over SignalLine AND MACDLine < 0 Then
    Buy ("MACD黃金交叉") next bar at market;

If MACDLine Crosses Under SignalLine AND MACDLine > 0 Then
    SellShort ("MACD死亡交叉") next bar at market;

// 柱狀體翻正/翻負也是進場訊號
If Histogram Crosses Over 0 Then
    Buy ("柱狀體翻正") next bar at market;

If Histogram Crosses Under 0 Then
    SellShort ("柱狀體翻負") next bar at market;

布林通道策略(Bollinger Bands)

// ====== 布林通道策略 ======
Inputs: BBLen(20), BBStd(2);
Variables: MidBand(0), UpperBand(0), LowerBand(0);

MidBand = Average(Close, BBLen);
UpperBand = MidBand + BBStd * StandardDev(Close, BBLen, 1);
LowerBand = MidBand - BBStd * StandardDev(Close, BBLen, 1);

// 價格跌破下軌後回到軌道內 → 逢低買進
If Close[1] < LowerBand[1] AND Close > LowerBand Then
    Buy ("布林下軌回升") next bar at market;

// 價格突破上軌後回到軌道內 → 逢高放空
If Close[1] > UpperBand[1] AND Close < UpperBand Then
    SellShort ("布林上軌回落") next bar at market;

// 停利停損
If MarketPosition = 1 Then Begin
    Sell ("布林中軌停利") next bar at MidBand Limit;
    Sell ("布林停損") next bar at EntryPrice - 100 Stop;
End;

If MarketPosition = -1 Then Begin
    BuyToCover ("布林中軌停利") next bar at MidBand Limit;
    BuyToCover ("布林停損") next bar at EntryPrice + 100 Stop;
End;

KD 指標(隨機指標)策略

// ====== KD 策略 ======
Inputs: KLen(9), KSmooth(3), DSmooth(3);
Variables: KValue(0), DValue(0);

// 計算 K 值和 D 值
Value1 = Highest(High, KLen) - Lowest(Low, KLen);
If Value1 > 0 Then
    Value2 = (Close - Lowest(Low, KLen)) / Value1 * 100
Else
    Value2 = 0;

KValue = Average(Value2, KSmooth);  // %K
DValue = Average(KValue, DSmooth);  // %D

// 在低檔區 K 值穿越 D 值向上 → 買進
If KValue Crosses Over DValue AND KValue < 30 Then
    Buy ("KD黃金交叉") next bar at market;

// 在高檔區 K 值穿越 D 值向下 → 放空
If KValue Crosses Under DValue AND KValue > 70 Then
    SellShort ("KD死亡交叉") next bar at market;

除錯技巧:Print 和 MessageLog

寫策略一定會碰到 bug,這兩個功能是你的好幫手。

Print(輸出到 Output 視窗)

// 印出文字
Print("策略開始執行");

// 印出變數值
Print("收盤價 = ", NumToStr(Close, 2));
Print("K棒編號 = ", NumToStr(BarNumber, 0));

// 印出多個資訊在同一行
Print("日期:", NumToStr(Date, 0),
      " 時間:", NumToStr(Time, 0),
      " 收盤:", NumToStr(Close, 0),
      " 均線:", NumToStr(Average(Close, 20), 2));

// 只在進場時印(避免 Output 被灌爆)
If MarketPosition = 1 AND MarketPosition[1] <> 1 Then
    Print("多單進場 價格:", NumToStr(Close, 0));

MessageLog(輸出到 Message Log)

MessageLog 適合即時盤中監控用,輸出會顯示在 MultiCharts 的 Message Log 面板。

// 當自動下單觸發時記錄
If MarketPosition <> MarketPosition[1] Then Begin
    If MarketPosition = 1 Then
        MessageLog(">>> 多單進場 @", NumToStr(Close, 0));
    If MarketPosition = -1 Then
        MessageLog(">>> 空單進場 @", NumToStr(Close, 0));
    If MarketPosition = 0 Then
        MessageLog(">>> 平倉出場 @", NumToStr(Close, 0));
End;

常見除錯方法

  1. 策略沒有訊號——在每個 If 條件前面加 Print,看看條件值是多少,是哪一關沒過
  2. 訊號太多——檢查是不是少了 MarketPosition 的判斷,導致已經持倉還一直重複進場
  3. 數值看起來不對——用 Print 逐行印出計算過程,跟手算的結果比對
  4. 即時盤行為和回測不同——加上 intrabarpersist 確認變數沒有被 tick 更新重設

進階語法:幾個實用的小技巧

Once 關鍵字(只在第一根 K 棒執行一次)

Once Begin
    Print("===== 策略啟動 =====");
    Print("參數: FastLen=", NumToStr(FastLen, 0),
          " SlowLen=", NumToStr(SlowLen, 0));
End;

時間過濾(只在特定時段交易)

// 台指期只在 9:00~13:00 之間開新倉
Inputs: TradeStart(0900), TradeEnd(1300);

If Time >= TradeStart AND Time <= TradeEnd Then Begin
    // 你的進場邏輯寫在這裡
    If FastMA Crosses Over SlowMA Then
        Buy next bar at market;
End;

// 13:30 前強制平倉(當沖收盤前)
If Time >= 1325 AND MarketPosition <> 0 Then Begin
    If MarketPosition = 1 Then
        Sell ("當沖收盤平倉") next bar at market;
    If MarketPosition = -1 Then
        BuyToCover ("當沖收盤平倉") next bar at market;
End;

NumToStr 和 Text 格式化

// NumToStr(數值, 小數位數)
Print( NumToStr(Close, 2) );        // "18250.00"
Print( NumToStr(BarNumber, 0) );    // "1523"

// 字串拼接用逗號
Print("收盤價是 ", NumToStr(Close, 0), " 點");

DLL Import(呼叫外部函式庫)

// 宣告外部 DLL 函數
DefineDLLFunc: "C:\MyDLL\Analysis.dll", int, "CalcSignal", double, int;

// 呼叫
Variables: ExternalSignal(0);
ExternalSignal = CalcSignal(Close, 20);

If ExternalSignal = 1 Then
    Buy next bar at market;

DLL Import 的用途很廣,你可以用 C# 寫一個機器學習推論引擎,打包成 DLL 讓 PowerLanguage 呼叫。不過這是進階用法,需要有 C# 或 C++ 的開發能力。

寫策略的 5 個實戰建議

1. 先寫虛擬碼,再寫程式碼

動手寫之前,先用中文描述你的策略邏輯。例如:

寫清楚之後,翻譯成 PowerLanguage 就簡單多了。

2. 每支策略只做一件事

不要把多空策略、停損停利、時間過濾、部位控制全部寫在同一段。拆成獨立的模組,用 Variables 傳遞狀態,日後維護起來才不會頭痛。

3. 參數不要超過 5 個

參數太多,最佳化的時候容易 over-fit。一支好的策略,核心邏輯通常只有 2~3 個關鍵參數。

4. 一定要考慮滑價和手續費

回測設定裡把滑價設定為 1~2 tick,手續費照實際情況填。很多看起來很賺的策略,加上交易成本之後就變成虧損。

5. 善用 PowerLanguage Editor 的語法提示

打字的時候按 Ctrl+Space 會跳出自動完成建議,不確定函數名稱的時候很好用。按 F1 可以直接看內建函數的說明文件。

常見問題 FAQ

PowerLanguage 是 MultiCharts 的程式語言,語法和 TradeStation 的 EasyLanguage 高度相容(約 95% 語法相同)。主要差異在於部分進階函數名稱不同,以及 PowerLanguage 支援 .NET 框架整合。大部分 EasyLanguage 的程式碼可以直接貼到 PowerLanguage Editor 裡使用。

可以。PowerLanguage 的語法設計接近英文口語,比 Python 或 C++ 更容易入門。一支簡單的均線交叉策略只需要 10 行程式碼。建議先從修改現成的範例策略開始,慢慢熟悉語法結構,大約 2~4 週就能寫出自己的第一支策略。

最常見的原因有三個:(1) 策略需要的 K 棒數量比圖表上的資料多,例如計算 200 日均線但圖表只有 100 根 K 棒;(2) 條件設定太嚴格,歷史資料中沒有任何觸發點;(3) 商品的資料解析度不對,例如策略寫的是日線邏輯但套用在 1 分鐘圖上。

可以。PowerLanguage 支援透過 DLL Import 呼叫外部函式庫。你可以用 C#、C++ 寫好 DLL,再在 PowerLanguage 中宣告並呼叫。這讓你能整合機器學習模型、自訂指標計算、或串接外部資料源。語法範例:DefineDLLFunc: "MyDLL.dll", int, "MyFunction", int, double;

劉安清
劉安清

群益期貨營業員,專精 MultiCharts 程式交易與海外期貨。

📌 想了解更多?歡迎加入我的 LINE 好友,免費諮詢!

LINE 加好友免費諮詢
LINE 諮詢