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;
常見除錯方法
- 策略沒有訊號——在每個 If 條件前面加 Print,看看條件值是多少,是哪一關沒過
- 訊號太多——檢查是不是少了 MarketPosition 的判斷,導致已經持倉還一直重複進場
- 數值看起來不對——用 Print 逐行印出計算過程,跟手算的結果比對
- 即時盤行為和回測不同——加上
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. 先寫虛擬碼,再寫程式碼
動手寫之前,先用中文描述你的策略邏輯。例如:
- 當 5 日均線從下往上穿越 20 日均線,而且成交量大於前一根 K 棒 → 買進
- 買進後,如果虧損超過 50 點 → 停損出場
- 買進後,如果獲利超過 100 點 → 停利出場
寫清楚之後,翻譯成 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;