EasyTrader ArtNo 299
在前面幾篇介紹了投資組合(PortFolio Trader)運作的基本邏輯觀念與相關程式語法的說明,接下來我們就利用一個範例策略來做說明動量指標又叫MTM指標,其英文全稱是“Momentom Index”,是一種專門研究股價波動的中短期技術分析工具。 動量指數以分析股價波動的速度為目的,研究股價在波動過程中各種加速,減速,慣性作用以及股價由靜到動或由動轉靜的現象。動量指數的理論基礎是價格和供需量的關係。
策略的邏輯是計算動量指標百分比來評估投資組合內所有商品,透過資金管理訊號來作指標排序,並依據排序的優先順序來決定投組內那些商品要做多,或那些商品要作空。策略內也加上了簡單的交易口數計算與出場方式
Portfolio_Rotation Signal 交易策略內容與說明
(這個策略是加在投組的訊號策略內)
//動量指標百分比做為投組每個商品每根K棒的計算評估基準
inputs:Formula(PercentChange(close, 14));
variables: formulaValue(0);
formulaValue = Formula;
//判斷交易策略是否在投組交易APP內執行
if getappinfo(aiisportfoliomode) <> 1 then
raiseruntimeerror("Signal can be used in Portfolio only.");
//將動量指標百分比數值formulaValue 存在變數RotationalValue 內
pmm_set_my_named_num("RotationalValue", formulaValue);
//建立作多/作空進場訊號
buy("LE") next bar at Highest(Close,5) stop ;
sellshort("SE") next bar at Lowest(Close,5) stop ;
//將各商品的部位狀態以 pmm_set_my_status 關鍵詞存放
pmm_set_my_status(iffstring(marketposition = 0, "Flat",iffstring(marketposition = 1, "Long", "Short")));
// 資金分配
var: PotentialEntryPrice(close), MoneyCostForInvestPerCtrct(0);
if (entryprice > 0) then PotentialEntryPrice = entryprice;
//計算每筆交易成本 = 保證金+最大潛在損失(這部分可以在投資組合設定畫面內輸入)
MoneyCostForInvestPerCtrct =
pmms_calc_money_cost_for_entry_per_cntrct(PotentialEntryPrice, Portfolio_GetMarginPerContract)+
pmms_calc_money_cost_for_entry_per_cntrct(PotentialEntryPrice, Portfolio_GetMaxPotentialLossPerContract);
//如果交易成本小於0則輸出錯誤信息
if 0 > MoneyCostForInvestPerCtrct then
raiseruntimeerror( text("Error! Price = ", PotentialEntryPrice:0:6, ", PMargin = ", Portfolio_GetMarginPerContract, ", PMaxPLoss = ", Portfolio_GetMaxPotentialLossPerContract));
// 將商品貨幣轉換成投組貨幣並存入變數 MoneyCostForInvestPerCtrct
pmm_set_my_named_num("MoneyCostForInvestPerCtrct", pmms_to_portfolio_currency(MoneyCostForInvestPerCtrct));
// 出場條件
inputs: StopLossPcntsOfPortfolio(0.1), ProfitTargetPcntsOfPortfolio(0.1);
variable: value(0);
setstopposition;
//以投組總權益的千分之一做為停損/停利的基準(會先將貨幣匯率作轉換)
value = StopLossPcntsOfPortfolio * 0.01 * Portfolio_Equity;
setstoploss(convert_currency(datetime[0], portfolio_CurrencyCode, SymbolCurrencyCode, value));
value = ProfitTargetPcntsOfPortfolio * 0.01 * Portfolio_Equity;
setprofittarget(convert_currency(datetime[0], portfolio_CurrencyCode, SymbolCurrencyCode, value));
Portfolio_Rotation_MM Signal資金管理訊號內容與說明(管理並決定進場交易的商品)
(這個策略是加在投資組合設定的資金管理訊號內)
//清除 PowerEditor 內 Debug輸出視窗內的信息
once cleardebug;
//允許作多及作空的商品數量
inputs:BuyBestX(3),SellWorstY(3);
//是否輸出 Log信息
Input: use_logging(false);
variables: idx(0), strategyIdx(0), strategyValue(0);
//宣告儲存商品索引碼與動量變動百分比數值的二維陣列並賦予初值-1
arrays: allStrategies[10000, 1](-1);
//判斷資金管理訊號是否在投組交易APP內執行
if getappinfo(aiisportfoliomode) <> 1 then
raiseruntimeerror("Signal can be applied (as Money Management Signal) in Portfolio only.");
//若輸入參數 BuyBestX + SellWorstY 大於參與交易商品的總數量pmms_strategies_count則輸出錯誤信息
if pmms_strategies_count < BuyBestX + SellWorstY then
raiseruntimeerror(text("Portfolio has not enough instruments: instruments number = ", pmms_strategies_count, "; BuyBestX = ", BuyBestX, "; SellWorstY = ", SellWorstY));
//停止所有策略進場建立部位
pmms_strategies_deny_entries_all;
//將所有商品索引碼及動量變動百分比數值存入陣列
for strategyIdx = 0 to pmms_strategies_count - 1 begin
strategyValue = pmms_get_strategy_named_num(strategyIdx, "RotationalValue");
allStrategies[strategyIdx , 0] = strategyValue;
allStrategies[strategyIdx , 1] = strategyIdx;
end;
//將陣列作遞減排序
Sort2DArrayByKey(allStrategies, pmms_strategies_count, 1);
//宣告變數與兩個動態陣列
variables: inLong(0), inShort(0);
arrays: strategiesLong[](-1), strategiesShort[](-1);
//將作多未平倉的商品數量存入變數 inLong (陣列內存的是作多未平倉商品的索引碼)
inLong = pmms_strategies_in_long_count(strategiesLong);
//將作空未平倉的商品數量存入變數 inShort (陣列內存的是作空未平倉商品的索引碼)
inShort = pmms_strategies_in_short_count(strategiesShort);
//輸出作多/作空的商品數量
if use_logging then
print( "strategies in position: long=",inLong, ", short=", inShort );
var : cur_idx(0);
//選擇動量變動百分比前 N名的商品索引碼
for idx = 0 to BuyBestX - 1 begin
//取得商品索引碼
cur_idx = allStrategies[idx, 1];
//如果該商品索引碼不在作多未平倉的陣列內,允許該商品建立多單部位,否則將該商品位置以-1填入
if (not array_contains(strategiesLong, cur_idx)) then
pmms_strategy_allow_long_entries(cur_idx)
else
strategiesLong[array_indexof(strategiesLong, cur_idx)] = -1;
//輸出作多的商品名稱
if use_logging then
print( "strategy ", pmms_strategy_symbol(cur_idx), "long entry" );
//如果有口數分配需求,則依資金分配計算交易口數
if UsePortfolioMoneyPcnt then
pmms_strategy_set_entry_contracts(
cur_idx,
pmms_calc_contracts_for_entry( PortfolioMoneyPcntForEntry, cur_idx )
);
end;
//選擇動量變動百分比後N名的商品索引碼
for idx = pmms_strategies_count - 1 downto pmms_strategies_count - SellWorstY begin
//取得商品索引碼
cur_idx = allStrategies[idx, 1];
//如果該商品索引碼不在作空未平倉的陣列內,允許該商品建立空單部位,否則將該商品位置以-1填入
if (not array_contains(strategiesShort, cur_idx)) then
pmms_strategy_allow_short_entries(cur_idx)
else
strategiesShort[array_indexof(strategiesShort, cur_idx)] = -1;
//輸出作空的商品名稱
if use_logging then
print( "strategy ", pmms_strategy_symbol(cur_idx), "short entry" );
//如果有口數分配需求,則依資金分配計算交易口數
if UsePortfolioMoneyPcnt then
pmms_strategy_set_entry_contracts(
cur_idx,
pmms_calc_contracts_for_entry( PortfolioMoneyPcntForEntry, cur_idx )
);
end;
// 強迫多單部位平倉(如果多單陣列內的商品索引碼不是-1,則將該商品平倉)
for idx = 0 to inLong - 1 begin
value1 = strategiesLong[idx];
if value1 >= 0 then begin
pmms_strategy_close_position(value1);
//輸出被平倉的商品名稱
if use_logging then
print( "strategy ", pmms_strategy_symbol(value1), "force position close" );
end;
end;
// 強迫空單部位平倉(如果空單陣列內的商品索引碼不是-1,則將該商品平倉)
for idx = 0 to inShort - 1 begin
value1 = strategiesShort[idx];
if value1 >= 0 then begin
pmms_strategy_close_position(value1);
//輸出被平倉的商品名稱
if use_logging then
print( "strategy ", pmms_strategy_symbol(value1), "force position close" );
end;
end;
// 決定是否做口數分配與可分配資金
inputs:
UsePortfolioMoneyPcnt(False),
PortfolioMoneyPcntForEntry(1);
if use_logging then
print("------------------------------------------------------------------")
為了方便測試,我將不同的商品指數都以日K方式匯入20010101~20180531資料,在QM裡的設定都比照台指期,並放入投資組合內,主策略訊號檔為上文中的 Portfolio_Rotation, 而資金管理訊號檔為 Portfolio_Rotation_MM
針對12個商品只選出指標排名前6個作多單進場(不作空單)的績效表現
allStrategies[strategyIdx , 0] = strategyValue;
allStrategies[strategyIdx , 1] = strategyIdx;
end;
//將陣列作遞減排序
Sort2DArrayByKey(allStrategies, pmms_strategies_count, 1);
//宣告變數與兩個動態陣列
variables: inLong(0), inShort(0);
arrays: strategiesLong[](-1), strategiesShort[](-1);
//將作多未平倉的商品數量存入變數 inLong (陣列內存的是作多未平倉商品的索引碼)
inLong = pmms_strategies_in_long_count(strategiesLong);
//將作空未平倉的商品數量存入變數 inShort (陣列內存的是作空未平倉商品的索引碼)
inShort = pmms_strategies_in_short_count(strategiesShort);
//輸出作多/作空的商品數量
if use_logging then
print( "strategies in position: long=",inLong, ", short=", inShort );
var : cur_idx(0);
//選擇動量變動百分比前 N名的商品索引碼
for idx = 0 to BuyBestX - 1 begin
//取得商品索引碼
cur_idx = allStrategies[idx, 1];
//如果該商品索引碼不在作多未平倉的陣列內,允許該商品建立多單部位,否則將該商品位置以-1填入
if (not array_contains(strategiesLong, cur_idx)) then
pmms_strategy_allow_long_entries(cur_idx)
else
strategiesLong[array_indexof(strategiesLong, cur_idx)] = -1;
//輸出作多的商品名稱
if use_logging then
print( "strategy ", pmms_strategy_symbol(cur_idx), "long entry" );
//如果有口數分配需求,則依資金分配計算交易口數
if UsePortfolioMoneyPcnt then
pmms_strategy_set_entry_contracts(
cur_idx,
pmms_calc_contracts_for_entry( PortfolioMoneyPcntForEntry, cur_idx )
);
end;
//選擇動量變動百分比後N名的商品索引碼
for idx = pmms_strategies_count - 1 downto pmms_strategies_count - SellWorstY begin
//取得商品索引碼
cur_idx = allStrategies[idx, 1];
//如果該商品索引碼不在作空未平倉的陣列內,允許該商品建立空單部位,否則將該商品位置以-1填入
if (not array_contains(strategiesShort, cur_idx)) then
pmms_strategy_allow_short_entries(cur_idx)
else
strategiesShort[array_indexof(strategiesShort, cur_idx)] = -1;
//輸出作空的商品名稱
if use_logging then
print( "strategy ", pmms_strategy_symbol(cur_idx), "short entry" );
//如果有口數分配需求,則依資金分配計算交易口數
if UsePortfolioMoneyPcnt then
pmms_strategy_set_entry_contracts(
cur_idx,
pmms_calc_contracts_for_entry( PortfolioMoneyPcntForEntry, cur_idx )
);
end;
// 強迫多單部位平倉(如果多單陣列內的商品索引碼不是-1,則將該商品平倉)
for idx = 0 to inLong - 1 begin
value1 = strategiesLong[idx];
if value1 >= 0 then begin
pmms_strategy_close_position(value1);
//輸出被平倉的商品名稱
if use_logging then
print( "strategy ", pmms_strategy_symbol(value1), "force position close" );
end;
end;
// 強迫空單部位平倉(如果空單陣列內的商品索引碼不是-1,則將該商品平倉)
for idx = 0 to inShort - 1 begin
value1 = strategiesShort[idx];
if value1 >= 0 then begin
pmms_strategy_close_position(value1);
//輸出被平倉的商品名稱
if use_logging then
print( "strategy ", pmms_strategy_symbol(value1), "force position close" );
end;
end;
// 決定是否做口數分配與可分配資金
inputs:
UsePortfolioMoneyPcnt(False),
PortfolioMoneyPcntForEntry(1);
if use_logging then
print("------------------------------------------------------------------")
為了方便測試,我將不同的商品指數都以日K方式匯入20010101~20180531資料,在QM裡的設定都比照台指期,並放入投資組合內,主策略訊號檔為上文中的 Portfolio_Rotation, 而資金管理訊號檔為 Portfolio_Rotation_MM
針對12個商品只選出指標排名前6個作多單進場(不作空單)的績效表現
針對12個商品只選出指標排名後6個作空單進場(不作多單)的績效表現
這篇文章很有料,真厲害!
回覆刪除謝謝您對部落格的關注
回覆刪除看完後,突然感到我的層次原來那麼低,又有事可忙了
回覆刪除學無止境
回覆刪除激讚! PMM 學習中。
回覆刪除給你按個讚
回覆刪除