来週から、1週間ほど新潟に帰省します。
FXトレードの予定については、
- 裁量トレード: 基本的にお休み。これまでの反省等を予定、、、と言いつつ、多分しない
- EAによる自動売買: 通常通りトレード予定
ここで問題になるのが、自動売買は複利運用をしていて、日次の頻度でリスク計算をし直している点。
”リスク計算”の作業としては、
- MT4のトレード結果をCSVファイルに落とす
- 1のCSVファイルをAccessに取り込み、日単位で集計した単利成績のトレード明細を作成する
- 2を入力として、オプティマルfによる最適掛け率の再計算と、相関係数によるトレード間の関連性によるリスク調整の実施を行う
- 3の結果をAccessに取り込んで、新しく計算された掛け率と、これまでのトレード成績結果による資産増減を加味して、次回のトレードロットを決定する
- 次回トレードロットに増減が発生したEAについて、トレードロット調整をちまちま実施する(これはVPS上の作業)
帰省中は、Officeが稼働するPCが手配できないため、上記作業の2、3、4ができない見通し。
2と3の掛け率調整については、直近の数値を固定で使用すればいいかなと妥協できるのですが、4のトレードロット計算だけは何とかしなくては。
いろいろ悩んだ結果、4のロット調整作業については、iOSのExcelを駆使して何とか対応する予定です。
iOSのExcelにあって欲しい機能として、
- データの並べ替え機能 -> これはあった
- データをフィルタして、その単位で値を集計する機能 -> これもあった
- あるデータをキーとして、キー毎に値を集計する機能 -> 残念、なさそう
というわけで、”どの戦略が”、”いくらの結果を出したか”というCSVファイルを用意して、iPhoneと格闘しながら、電卓も使ってちまちまトレードロットを計算する方針になりそうです。
こんな、CSVファイルをMT4から取得するスクリプトを作成して、そのスクリプトをVPS上のMT4に仕込みました。
以前作成した、ステートメントCSV作成スクリプトを改造しました。
iPhone上のExcelでは、このような明細をソートして、戦略毎にフィルタリングしてトレード成績を集計する予定です。
もっと凝ったMT4スクリプトを作れればよかったのですが、これが今の精一杯。
コード的には、こんな感じ。
RDBのUpdate機能も強引に関数化して、各明細がどの戦略のトレードかをマジックナンバーをもとに見分けられるようにしました。
//+------------------------------------------------------------------+
//| StatementToCSV.mq4 |
//| Copyright 2015, Life with FX |
//| http://lifewithfx.jp |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Life with FX"
#property link "http://lifewithfx.jp"
#property version "1.40Z"
#property strict
#property show_inputs
extern string CSVOutputFolder = "-- MT4 MQL4/Files folder --";
extern bool OutputRecordDescendingOrder = false;
extern bool OutputHeaderRecord = true;
extern string ReportPeriod = "-- PeriodFilter: Order close time base --";
extern bool UsePeriodFilter = true;
extern int ReportFromDate = 20150801;
extern int ReportToDate = 20159999;
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
int OnStart()
{
int hFile = -1;
int historyTotal = OrdersHistoryTotal();
if(historyTotal <= 0)
{
Print("No History Data. Skip process...");
return(0);
}
int ticket[];
ArrayResize(ticket, historyTotal);
ArrayInitialize(ticket, -1);
for(int i=0; i<historyTotal; i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
{
switch(OrderType())
{
case OP_BUY:
case OP_SELL:
ticket[i] = OrderTicket();
break;
default:
ticket[i] = -1;
}
}
}
// output filename StatementCSV_YYYYMMDD_HHMM.csv
string fileName = "StatementCSV_" + Year();
if(Month() < 10) { fileName = fileName + "0" + Month(); }
else { fileName = fileName + Month(); }
if(Day() < 10) { fileName = fileName + "0" + Day() + "_"; }
else { fileName = fileName + Day() + "_"; }
if(Hour() < 10) { fileName = fileName + "0" + Hour(); }
else { fileName = fileName + Hour(); }
if(Minute() < 10) { fileName = fileName + "0" + Minute(); }
else { fileName = fileName + Minute(); }
fileName = fileName + ".csv";
Print("output filename: " + fileName);
//get handle
hFile = FileOpen(fileName, FILE_BIN|FILE_WRITE, ",");
if(hFile < 0) {
Print("error abort: output file creation error!!");
return(-1);
}
// CSV Record Header
string header = "ID,TradeProfit" + "\r\n";
if (OutputHeaderRecord) {
FileWriteString(hFile, header, StringLen(header));
}
const string ITEM_SEPARATOR = ",";
int startIdx;
int idxStep;
int ordersLastIdx = historyTotal - 1;
double pipScale;
double pipScaleDigits;
double takeprice;
double takepips;
if (!OutputRecordDescendingOrder) {
startIdx = 0;
idxStep = 1;
} else {
startIdx = ordersLastIdx;
idxStep = -1;
}
for (int i = startIdx; !(i < 0 || ordersLastIdx < i) ; i += idxStep) {
if(ticket[i] != -1) {
if(OrderSelect(ticket[i], SELECT_BY_TICKET, MODE_HISTORY)) {
// PeriodRangeFilter
string closeDateStr = TimeToStr(OrderCloseTime(), TIME_DATE);
int closeDateInt = StrToInteger(StringSubstr(closeDateStr, 0, 4) + StringSubstr(closeDateStr, 5, 2) + StringSubstr(closeDateStr, 8, 2));
if (!UsePeriodFilter) {
// OK
} else if (ReportFromDate <= closeDateInt &&
closeDateInt <= ReportToDate) {
// OK
} else {
continue;
}
string output = getSID(OrderMagicNumber(), StringSubstr(OrderComment(), 0, 2)) + "_" + StringSubstr(OrderSymbol(), 0, 6) + ITEM_SEPARATOR;
output = output + (NormalizeDouble(OrderSwap(), 2) + NormalizeDouble(OrderCommission(), 2) + OrderProfit());
output = output + "\n";
FileSeek(hFile, 0, SEEK_END);
FileWriteString(hFile, output, StringLen(output));
}
}
}
if(0 < hFile) {
FileClose(hFile);
}
Print ("works fine: finished!!");
return(0);
}
string getSID(int magic, string comment) {
if (magic == 62345678) { return "ince";}
else if (magic == 39404940) { return "WZ";}
else if (magic == 8301908) { return "sp";}
else if (magic == 20142301) { return "Be";}
else if (magic == 2328104) { return "BTGYA";}
else if (magic == 4668) { return "REV";}
else if (magic == 10101) { return "FDS1";}
else if (magic == 4698523) { return "WALL";}
else if (magic == 2328105) { return "BTJU";}
else if (magic == 7730773) { return "WB3as1";}
else if (magic == 728811) { return "IET";}
else if (magic == 728822) { return "IET";}
else if (magic == 728833) { return "IET";}
else if (magic == 527411) { return "IMTL1";}
else if (magic == 527422) { return "IMTL1";}
else if (magic == 110101) { return "FDS1";}
else if (magic == 310101) { return "FDS1";}
else if (magic == 9930993) { return "WBV3";}
else if (magic == 12780) { return "Kel2";}
else if (magic == 8830883) { return "WBV3BB";}
else if (magic == 20142302) { return "Be";}
else if (magic == 987) { return "EW";}
else if (magic == 213002) { return "GEKI";}
else if (magic == 213001) { return "GEKI";}
else if (magic == 8881908) { return "sp";}
else if (magic == 2014061051) { return "Ri";}
else if (magic == 2014061052) { return "Ri";}
else if (magic == 2014061053) { return "Ri";}
else if (magic == 2014061054) { return "Ri";}
else if (magic == 2014061011) { return "Ri";}
else if (magic == 2014061012) { return "Ri";}
else if (magic == 2014061013) { return "Ri";}
else if (magic == 2014061014) { return "Ri";}
else if (magic == 527433) { return "IMTL2";}
else if (magic == 78942) { return "Ven";}
else if (magic == 514229) { return "Mone";}
else if (magic == 213003) { return "GEKI";}
else if (magic == 1987) { return "MEW";}
else if (magic == 19202920) { return "WZ";}
else if (magic == 11200) { return "Ra";}
else if (magic == 753159) { return "Rac1";}
else if (magic == 2014061095) { return "Ri";}
else if (magic == 2014061093) { return "Ri";}
else if (magic == 2014061094) { return "Ri";}
else if (magic == 2014061096) { return "Ri";}
else if (magic == 7703304) { return "duet";}
else if (magic == 4565450) { return "WLAsia";}
else if (magic == 4565451) { return "WLAsia";}
else if (magic == 4565452) { return "WLAsia";}
else if (magic == 4565453) { return "WLAsia";}
else if (magic == 4565454) { return "WLAsia";}
else if (magic == 4565455) { return "WLAsia";}
else if (magic == 736211) { return "IW";}
else if (magic == 7703303) { return "duet";}
else if (magic == 5551101) { return "Union";}
else if (magic == 7021013) { return "Legato";}
else if (magic == 5551102) { return "Union";}
else if (magic == 5551103) { return "Union";}
else if (magic == 728711) { return "IETAX";}
else if (magic == 728722) { return "IETAX";}
else if (magic == 728733) { return "IETAX";}
else if (magic == 4051220) { return "BC7";}
else if (magic == 728511) { return "IETCM";}
else if (magic == 728522) { return "IETCM";}
else if (magic == 728533) { return "IETCM";}
else if (magic == 286411) { return "STCM";}
else if (magic == 813711) { return "IEGL";}
else if (magic == 813722) { return "IEGL";}
else if (magic == 813733) { return "IEGL";}
else if (magic == 2328100) { return "BTR";}
else if (magic == 20150601) { return "VBS";}
else if (magic == 20150602) { return "VBS";}
else if (magic == 20150603) { return "VBS";}
else if (magic == 10006) { return "SILV";}
else if (magic == 10007) { return "SILV";}
else if (magic == 10008) { return "SILV";}
else { return comment; }
}
