正確にチャートを同期させる00-TimeSync_v101.mq4を script 化する。

ジム・ジャロース
こんにちは。

00-timesync_v101_modbyfai.mq4ですが、たまったタスクが悪さをして不可解な挙動が多いため自分的には使えない感じですので、scriptにしてドラックアンドドロップした時に1度だけ同期を実行するように改造しようと試みたのですが、APIの部分が理解できず、ペンディング状態です。
もし、ご無理でなければ、scriptを作っていただけないでしょうか。n(_ _)n
興味のないネタでしたら華麗にスルーしていただいて結構ですが。(;^_^A

これは・・・確かにAPIをよく知らないと出来ないので、こちらに用意しました。


・インジケータとスクリプトでは、実行時のスレッドが異なる。
インジケータはウィンドウを表示しているスレッドで動いているので、SetFocus()が可能だが、スクリプトは別のスレッドなので、SetFocus()できず、代わりに SetForegroundWindow()を使う必要がある。(SetForegroundWindowでも、見た目はアクティブにならないが、キーイベントだけは送れるようになる。)


スクリプトを実行するウィンドウは必ずしもアクティブとは限らない。
ナビゲーターウィンドウからスクリプトを非アクティブなウィンドウにドロップすることもあり得るので、GetTopWindow()でアクティブなウィンドウを取得してから、GetWindow(hWnd,2)で次のウィンドウを取得する必要がある。


・・・という点に注意して改造する必要がありました。
実行時の確認ダイアログが煩わしい人は、
#property show_inputs
の一行を削除してください。



ちなみに、AutoHotkey の Accela.ahk を使用していると正常動作しません。(数字入力が被ってしまうため..)

1::
   if CheckFN()==0
     PostMessage, 0x111,33137,0  ;Period M1
   else
     Send 1
  return

↑Accela.ahk で、1から9の数字にショートカットを割り当てている部分をすべて削除するか、

#1::
   if CheckFN()==0
     PostMessage, 0x111,33137,0  ;Period M1
   else
     Send 1
  return

↑ # を加えて「Win + 1」に割り当てる等で回避してください。

ヒストグラムを描く

統計学の基本は、データを観察することにあるのであ〜る。

‥‥という訳で、ヒストグラムを表示させるインジケータをこちらに作りました。
階級幅の自動決定には、フリードマン=ダイアコニスの選択を採用しています。(スタージェスの公式はサンプル数が多いと当てはまらないらしい..
階級幅を自分で指定したい場合は、ClassWidth で設定できます。
チャートをかなり縮小して表示させている人向けに、HistWidth で、ヒストグラム一本の柱の幅を何本の Bar で表示させるか?も指定できるようにしました。
平均や分散といった、基本統計量を計算する機能はありません。(平均よりも中央値、分散よりも Q3-Q1幅の方が好きなので...。必要な人は自分で改造してくださいっ



↑過去何本目から何本分のデータを対象とするか?を指定すれば、異なる期間のデータを比較できます。
二つのグラフで自動計算した階級幅が異なる場合は直接指定してください。
グラフの右側を揃えるために、FixedMinimum を同一の値(0)に設定してください。
現在の値は、赤塗りされた位置で分かります。


上のグラフは、EURUSD の週足で、直近の過去1年(下段)と、その前の一年(上段)の高値-安値 の幅の分布を示しています。
中央値でみると、120pips も振れ幅が減っていることがわかります。。。
これでは、ボラティリティの低下に嘆くトレーダーが増えているのも仕方ないですね。。^^;

MetaTrader4 から別のエディタを選択して起動する。

Notepad++ de MQL4の記事を読んで、『A better editor for MQL4 using SciTE!』を導入してみたら、かなり便利だった...のですが、微妙に欠点があって、やはり純正 MetaEditor も手放せなかったりします。
そこで、MetaTrader4 から、両方のエディタを選んで起動できるようにしてみました。
動作イメージは・・・

↑MT4から起動すると
↓選択ダイアログがでて、「はい」 ならMetaEditor 、「いいえ」 なら SciTE が起動します。


手順は以下の通りです。
(1) MetaEditor.exe -> _MetaEditor.exe にリネームしておく。
(2) 以下の6行の MetaEditor.ahk を作成し、右クリ&コンパイルして MetaEditor.exe を作成して配置する。(要 AutoHotkey)

SetWorkingDir %A_ScriptDir%
MsgBox, 4,, Open MetaEditor ?
IfMsgBox Yes
    Run , %A_ScriptDir%\\_MetaEditor.exe "%1%"
else
    Run , "C:\\MT4\\scite-mql-1.4.2\\SciTE.exe" "%1%"

↑SciTE.exeのパスは適宜書き換えてください。

注意1)MetaTrader がアップデートされると、MetaEditor.exe が上書きされて元に戻ります。その場合は、やり直してください。
注意2)既に、MetaEditor.exe が起動している場合は、そちらがアクティブになるだけなので、SciTEは起動しません。





『A better editor for MQL4 using SciTE!』は、そのままでは日本語設定になっていないのと、キーワードの色設定が MetaEditor と異なっています。
このセットを解凍して、SciTE.exe のあるフォルダに上書きすると簡単に上記設定に変更できます。
メニューが日本語では困る人は、locale.properties ファイルを削除してください。


フォントを変えたい場合は、オプションから
SciTEGlobal.properties (共有特性設定)ファイルの下記を変更してください。
font.base=font:MS ゴシック,size:10


ツールの Code Beatifierでソース整形する際のオプションを変更する場合は、
Commands.properties ファイルの下記を変更してください。
command.14.*="$(SciteDefaultHome)\\additions\\astyle\\astyle.exe" -s2A3Dp "$(FileNameExt)"


コンパイラのパスを変えたい場合は、
langs/mql.properties ファイルの下記を変更してください。
metalang=$(SciteDefaultHome)\other\metalang.exe


#include しているファイルがある場合、metalang.exeのパスを本来のパスに変えるか、
scite-mql-1.4.2\other\experts\include
に必要なファイルを置くしかないようです。


デフォルトの補完機能では、MQL4のすべてのキーワードが補完候補には出てきません。不便であれば、
api\mql.api に追記しておくと改善します。とりあえず、これで上書きして、不要な単語を消すと良いかも?

EAで指標発表等を回避するには?

・・・と、どなたかに聞かれていたような気がするので方針だけ書いておきます。

1.ネット上で経済指標発表時刻一覧を公開しているサイトを探す。
2.定期的に自動取得して、EAに読み込む。

公開サイトとしては、
ForexFactoryhttp://www.forexfactory.com/ff_calendar_thisweek.xml や、
DailyFXhttp://www.dailyfx.com/files/Calendar-10-21-2012.csv (週単位でファイル名が変わります)
が知られています。

EAからデータ取得するとしたら、WinInet.mqh のようなライブラリを使うと

↑こんな感じで、↓のCSVデータが取得できます。

DailyFXのデータはCSVなので、MQL4では簡単に読めます。(ただし、文字コードUnicodeなので一部文字化けします。)
DailyFXの指標を表示させるインジケータがここにあるので、そのあたりを参考にすればよいと思います。


一方、ForexFactory のデータは、FFCal.mq4 が対応していて、EA から直接 iCustom 経由で直前直後にどのインパクトの指標発表があるのかを1つだけ取得できます。

↑EAでの書き方はこれだけです。一つのMT4内で、複数のEAで使う場合は、iCustom よりもグローバル環境変数を用いて情報共有させた方が良いかもしれません。



問題は、、、FFCal.mq4 自体があまり改良されていない点で、例えば、「SetIndexStyle(1, DRAW_NONE);//←本来は 2 」みたいなバグも相変わらず放置されています。
一定時間前に鳴るように Alert の設定をしても、希なタイミングで鳴らないこともあります。EAから呼ばれる際に、毎回、XMLファイルを読み取って、構文解析する処理も非効率です。(一度読んだ結果をメモリ上に保持しておけば良いはずなのに...)



指標インジケータ自体は、凝ったものがいくつかあるので作り込む気はないのですが、最低限のカスタマイズをしたものをこちらに用意しました。

・縦ライン表示機能の削除
・Alertは少し遅れても確実に鳴るように
・3個以上の指標時刻を表示可能に
XMLのデータは解析結果を保持
・既知の指標名は日本語表示可能に

などの変更を行っています。指標ボットを作りたい人向けの下地になれば良いかなと思ってます。

↑二段表示

↑日本語表示(!)


日本語表示は、同梱のCSVファイルによる置換をしているだけなので、適宜、正しい訳語に修正してお使いください。

デコンパイルすると動かないコード(?!)

先日みつけた、int 最小値バグを調べていて気づいたのが、表題の「デコンパイルすると動かないコード」です。正確には、「動かない」のではなくて、挙動が変わるだけですが、デコンパイラをお持ちの人は以下のコードを試してみてください。(ちなみに、Purebeamさんは、8/10 にデコンパイラの販売を停止されています..)


↑このコードをex4にコンパイルして実行すると、OK が表示されます。


↑先の ex4 をデコンパイルした結果がこのコードです。
これをコンパイルして実行すると、NG が表示されます。変数に設定した値がビミョーに変化しているのが分かります。



上記は単純な例ですが、デコンパイルで数値が変わる特性を利用して、大量の変数で複雑に分岐すれば、ある種のデコンパイル対策になるかもしれません。^^;

   int a = -2147483648;
   int b = -2147483647;
   int c = -2147483648;
   int d = -2147483647;
   ↓デコンパイル結果 (フラグ情報が失われる)
   int li_0 = -2147483647;
   int li_4 = -2147483647;
   int li_8 = -2147483647;
   int li_12 = -2147483647;
続きを読む

MQL4でXorShiftによる疑似乱数生成。-2147483648 > -2147483647-1 という不思議。

真面目な用途での乱数生成は、メルセンヌ・ツイスターが推奨で、MT4 であれば これExcel であれば、Excel乱数生成アドインがあります。


ただ、どうしても MQL4のみで、MathRand() より良さそうな乱数を使いたい時のために、XorShift による実装を用意しました。

int XorShiftRand(int seed = 123456789) { 
  static int x = 123456789;
  static int y = 362436069;
  static int z = 521288629;
  static int w = 88675123; 
  if(seed != 123456789) x = seed;
  
  int t;
 
  t = x ^ (x << 11);
  x = y; y = z; z = w;
  w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)); 
  return(w);// w = -2147483648~2147483647
}

使い方は、

XorShiftRand(GetTickCount());

で、最初に seedを設定し、以降は、XorShiftRand() で、-2147483648〜2147483647 の整数乱数を得ることができます。


ちなみに、1億回実行した時の実行時間は以下の傾向です。

関数 実行時間(ms)
MathRand 3479
XorShiftRand 7660
gsl_rng_uniform 16724

極端に遅くなることは無いようです。



-2147483648 > -2147483647-1 という不思議。

実用性はさておき、XorShift を調べていて気づいたのが MQL4 の不思議な挙動です。

int a = -2147483648;
int b = -2147483647-1;
if(a > b) Print("a > b");// TRUE 

↑ a と b は等しいはずなのに、a が大きくなります。


この現象は、int 型の最小値 -2147483648 のときのみ起こる・・・と信じたいところですが、未確認です。

int a = -2147483648.0; // 実数表記
int a = 0x80000000; // 16進表記

↑変則的に、このように宣言すれば、a == b が成立します。
これは苦肉の策ですが、、変数の型で定義される末端の数値を扱うときは注意しましょう。。orz






ランダムチャートのその後。


出来高に凶悪なコーシー分布のノイズを加えて、高騰/急落を再現してみました。
1.5秒毎にローソク足1本を追加して自動更新する機能も追加しました。
乱数に GSL も使えるようにしました。
http://ux.getuploader.com/fai_fx/download/318/RandomChart.zip
あくまでも、ベースとなる動きはコイントス方式のランダムウォークで、横軸=時間軸を出来高の調整で歪めているだけです。
実験用途や、週末に動くチャートを見たい時に活用ください。

MQL4のMathRand()の計算式は・・・

最悪のアフターエピソードというのはね。
長いことブログを書かないでいると、書き方すら忘れてしまうことだったんだ。
URLのリンクに title 属性付けるときはどう書くんだっけ?
引用部分を囲むのは > or >> or >| ?
画像のサイズ指定はどう書くの?
はてな記法なんて、ブログでしか使わないから、毎日書いていないと直ぐに忘れてしまう。(涙)


そんな時のために「はてな記法壁紙があるじゃないか!」と言われても、そこまでするモチベーションが湧かないよ...。(泣)




・・・とまぁ、本題に入る前に一発ネタを入れたほうが良いかなって書いてみたけど、これ以上続けるともっと哀しくなってゆくので、止めておきます。
さて、昨日紹介した、ランダムウォークのチャート作成スクリプトによる人工チャートと、実際の為替チャートとの違いは、いろいろあるのでしょうけど、分かりやすいところでは、指標発表時特有の動きの有無でしょうか。
価格が突然大きく動くジャンプ拡散過程のような要素が計算式に入っていないと長期間で見たとき少し違和感があります。




ただ、それ以前に、MQL4の MathRand() で乱数シミュレーションするのはどうよ? と思ったので、MathRand()の計算式を調べました。

int start()
  {
   MathSrand(100);
   MQ4Rand(100);// 同一のseedを設定する。
   for(int i=0;i<10;i++)
      Print(i+ " MathRand="+MathRand()+" MQ4Rand="+MQ4Rand());
  }
//+------------------------------------------------------------------+
int MQ4Rand(int seed = -1){
   static int x = 1;//Seed
   if(seed != -1){x = seed; return(0);}
   x = x*214013 + 2531011; // N倍して、Mを足すだけ....
   return((x >> 16) & 32767);
}

↑このスクリプトを実行した結果が、下図です。

MathRand と MQ4Rand が同一の結果を返していますので、計算式は合っていると思います。
この解説によると、これは線形合同法による乱数で、周期は 2147483648 だそうです。最下位ビットの周期は131072 になります。


つまり、、乱数値を2で割って余りを求めた場合、131073回目以降は同じ並びになるということです。

for(int i=1;i<=131072+10;i++){
   int x = MathRand();
   if(i<=10 || i>131072)
      Print(i+" mod="+ DoubleToStr(MathMod(x,2),0));
}

↑その確認用コードの結果が下図です。

見事に繰り返していますね。
MathRand の計算式が、実質わずか2行であることに驚き(2行なのに計算結果が想像つかない..)、その周期が想像よりはるかに短いという..。これこそが、最悪のアフターエピソードです。苦笑。


まとめ

『Expert advisor』は、おもしろい! で紹介されている、GSL(The GNU Scientific Library) であれば、デフォルト設定でメルセンヌ・ツイスタ(Mersenne twister)を乱数発生器として、 MQL4から使えるので、そちらを使いましょう..。