2012/01/12

GSLをMT4で使う■■■

再修正しました。2012/1/13
R以外で計算ライブラリーをMT4に導入する方法がないか調べてる内に、GSL(GNU Scientific Library)と言うものを発見しました。と言うことで今回は、GSLをMT4で使うことに挑戦してみました。

何はともあれまずこちらを・・

まずは、このサイトをご確認ください。 慣れた人ならこれでほぼ完了します。
1.GSLをWindowsのVisual C++で使う(ごんざぶログ)を熟読
2.産業技術総合研究所 富永氏によるマニュアルの和訳GSL リファレンス・マニュアルの日本語訳を確認
3.MQL4(MT4):DLLの作り方を公開していますアメンボのブログ2)内の記事および
記事の置き場所アメンボのWEB―記事:・MT4(MQL4)用DLLの作り方.pdf
4.初めてのDLL(2)/関数作成篇(ご存じfaiさんの備忘秘録)

組込方法

上記の記事を参考(ほぼそのまま^^;)に中継用のDLLを作成し、GSLをMT4から使用する事にしました。

手順1

今回は、VC++2010を使用してみたので、まずは、Visual C++ 2010 Express(無料)をDL+インストールします。
そして、VC++向けにコンパイルされたGSLをDLします。今回は、GSL_1.8__LCG_win32_vc71.tar.gzをDLしました。

手順2

まずは、GSL リファレンス・マニュアルの日本語訳を参考に取り込む関数を選択します。
今回は、第31章ウェーブレット変換P461~ を選択しました。
※参考コードも記載されていますので、導入しやすいと思います。
※注意:GSL リファレンス・マニュアルの日本語訳に記載されているサンプルコードは、C語で記載されていますが、VC++用のコードではありません。その為、VC++で使用する場合は、一部変更する必要があります。
例)
double *abs = malloc(10* sizeof (double));//というコードは、エラーが出ます。
double *abs = (double *)malloc(10 * sizeof (double));//という型宣言を追加する必要があります。

手順3

 ※ここに記載してあるのは、あくまでもDLL作成の最低設定です。詳細については、上記参照サイトを確認してください。
新規プロジェクトの作成
VC++2010を起動し【ファイル(F)】―【新規作成(N)】-【プロジェクト(P)】
Win32プロジェクトを選択後、名前(N)欄にプロジェクト名を記入-【OK】-【次へ】
※必要に応じ保存場所を変更。保存場所を覚えておく。
1
2
Win32アプリケーションウィザードにて(DLL)(空のプロジェクト)を選択-【OK】
3
プロジェクトが、立上ったらソリューションエクスプロラー内ソースファイルを右クリック-【追加】-【新しい項目】を選択。
【C++ファイル(.cpp)】-名前欄にファイル名を記入
※本来は、ヘッダーファイルなどに分割するが、今回はcppファイルのみを使用する。
4

GSLのインクルード
ここで一度VC++2010を終了後、先ほどDLしてきた、GSLファイルに移動し、解凍後最下層にある《includeフォルダ》及び《libフォルダ》をコピーし、VC++2010で作成したプロジェクトフォルダのC++ファイル(.ccp)があるフォルダ内にペーストする。
13

DEFファイルの作成
とりあえず、テキストエディタで空のファイルをプロジェクト名.defとし、C++ファイルがあるフォルダに作成する。
15

プロパティページの設定
※本来は、Debugモードで作成していくが、今回は説明短縮のため初めからReleaseで設定する。
ソリューション構成をReleaseに設定し、【プロジェクト(P)】-【プロパティ】を選択する。
【構成プロパティ】
【全般】━【文字セット】━(マルチバイド文字セットを使用する)
【C/C++】┳【プリプロセッサ】━【プリプロセッサの定義】━【(編集)】(GSL_DLL)を追加
             ┗【コード生成】━(マルチスレッド(/MT)に設定
6
【リンカー】┳【追加依存ファイル】━【(編集)】(.\lib\gsl.lib:.\lib\gslcblas.lib)を追加
              ┗【モジュール定義ファイル】━【(編集)】(先ほど作成したdefファイル名)を追加
7.6
7.3

コード記入
今回テスト用に記入したコードは、以下のとおりです。
※サンプルコードを少しいじっています。
#pragma once
#define WIN32_LEAN_AND_MEAN 
#include <Windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include ".\include\gsl\gsl_sort.h"
#include ".\include\gsl\gsl_wavelet.h"

BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
//----
switch(ul_reason_for_call)
{
 case DLL_PROCESS_ATTACH:
 case DLL_THREAD_ATTACH:
 case DLL_THREAD_DETACH:
 case DLL_PROCESS_DETACH:
 break;
}
//----
return(TRUE);
}
//-----------------------------------------------------------------------------
__declspec(dllexport) void __stdcall DWT(double *input,double *out,int Ns,int D,int fs){
 int i;
 int siz = (int)pow(2.0,Ns);
 if(D%2==1)D++;
 if(D>20)D=20;
 
 //配列のコピー
 memcpy(out,input,sizeof(double)*siz); 
 
 //ウェーブレットの初期設定(ウェーブレット名,D値)
 gsl_wavelet *w;
 if(D==2){
  w = gsl_wavelet_alloc(gsl_wavelet_haar,D);
 }else{
  w = gsl_wavelet_alloc(gsl_wavelet_daubechies, D);
   }
  
 //作業領域の確保(数量)
 gsl_wavelet_workspace *work;
 work = gsl_wavelet_workspace_alloc(siz);
 size_t *p = (size_t *)malloc(siz * sizeof(size_t));
 double *abs = (double *)malloc(siz * sizeof (double));
 if (abs == NULL || p== NULL){printf("メモリを確保できません"); exit(0);}
 
 //変換(初期設定,データ,進み幅,作業エリア)
 gsl_wavelet_transform_forward(w, out, 1, siz,work);
    
 //フィルタ作業
 for(i = 0; i < siz; i++) abs[i] = fabs(out[i]);
 gsl_sort_index(p, abs, 1, siz);
 for(i = 0; (i + fs) < siz; i++) out[p[i]] = 0;
    
 //逆変換
 gsl_wavelet_transform_inverse(w, out, 1, siz, work);
}
//----------------------------------------------------------------------------

DEFファイルの内容を記入
以下の様に作成しました。
LIBRARY GSLwrapper

EXPORTS
 DWT
 
ビルドと配置
ビルドに成功したら、Releaseフォルダ内のプロジェクト名.dllとlibuフォルダ内のgel.dllおよびgslcblas.dllをコピーし、MT4のlibrariesフォルダにプロジェクト.dllをペーストterminal.exe と同じフォルダ内にgel.dllおよびgslcblas.dllをペーストします。(追記)※教えて頂いた方ありがとうございます。


※再追記
上記コードをそのまま作動させるとメモリリークが発生するそうです。
修正方法は、コメント欄をご覧ください。


呼び出し側のMQL4のコードを作成
以下の様なサンプルコードを作成しました。
//+------------------------------------------------------------------+
//|                                                      DWT_GSL.mq4 |
//|                                        Copyright ゥ 2012, bighope |
//|                       http://expertadviser-bighope.blogspot.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright ゥ 2012, bighope"
#property link      "http://expertadviser-bighope.blogspot.com/"

#import "GSLwrapper.dll"
   void DWT(double& input[],double& out[],int Ns,int k,int fs);
#import

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Yellow

extern int       N = 10;//対象データ数(2のN乗)
extern int       D = 4;//ウェーブレットD数※2は、Harr
extern int       max = 50;//最大値からどれだけ残すか
extern int       Shift = 0;//データのシフト
double IDWT[];
double in[];
double out[];
int    DWTPeriod ;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//---- indicators
   SetIndexStyle(0,DRAW_LINE);
   SetIndexBuffer(0,IDWT);
  
   DWTPeriod = MathPow(2,N);
   
   ArrayResize(in,DWTPeriod);
   ArrayResize(out,DWTPeriod);
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
int deinit()
  {
//----
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
   int counted_bars=IndicatorCounted();
   if(counted_bars>0)return(0);
   ArrayInitialize(in,0.0);
   ArrayInitialize(out,0.0);
   for(int k=0;k<DWTPeriod;k++) in[k]=Open[k+Shift];
   
   DWT(in,out,N,D,max);
   
   for(k=0;k<DWTPeriod;k++)IDWT[Shift+k] = out[k];

   return(0);
  }
//+------------------------------------------------------------------+


手順4

MT4を作動させて、DWT_GSLを作動させてみる。
※インジケータのパラメータ【全般】の(ALL DLL imports) のチェックをいれること。
 16
テストの結果、Experts欄に【 DWT_GSL USDJPY,M5: cannot load library 'GSLwrapper.dll' (error 126)】と表示されインジケータが作動しなかった。ちなみに、XP32bit、MT4.00 Build409 を使用しています。
上記のようにエラーが発生した場合は、librariesフォルダにPathを通すことで対応します。
【マイコンピュータ】右クリック―【プロパティ(R)】―【詳細設定】―【環境変数(N)】―【システム環境変数(S)】
【Pathを選択】―【編集】―一番最後に【;C:\Program Files\MetaTrader 4\experts\libraries】と記入

※デフォルト設定の場合です。各MT4によって調整が必要です。
※\は、¥マークの半角です。
※Pathを追加するだなので、既存の情報を変更しないように注意してください。
作業を終了後MT4を立ち上げると、インジケータが表示されます。
18

サンプル

今回は、VC++2010で説明しましたが、汎用性を考慮してVC++2008で作成した物を添付しておきます。
ご興味のある方は、こちら よりDLしてください。

まとめ

GSLを取り込むことで、作業の低減とバグの低減が可能になると思います。
今回、一番手こずった点は、cannot load library でことごとくDLLを読み取ることが出来なかったところです。
筆者自身、いろいろとOSをいじりすぎているのでもしかしたら、Pathを通す必要がないかもししれません。
もし、Pathを通すことなくDLLが読み込めたとしたらコメントが頂けると幸いです。

2011/12/25

パターン認識の精度を向上させる。■■■

今回は、前回の内容を用いて認証精度の向上を図ってみました。
実は、ウェーブレットの事を調べていて、別階級のウェーブレット係数は、そのままでは比較できない事、もし比較する場合には、変換作業が必要であることがわかりました。その変換作業を用いることで認証制度の向上に取り組んだわけです。

スケール係数の比較は不要

スケール係数の数値を変更して確認してみました。以下がその画像です。
※白線:無加工 ※黄線:スケール係数+0.05 ※赤線:スケール係数+0.1
スケール
この画像でわかるとおり、波形の形状には変化がなく、位置が変化したにすぎません。その為、パターン認証では不要な要素であることがわかります。

ウェーブレット係数の変換作業

まず、変換作業に使用する重みを作成しました。
これは、ウェーブレット変換する際に乗算されるsqr(1/√2=0.70710678)を各階級に応じて除算するものです。
重み
変換作業を画像で見てみると、以下の図のとおりとなります。
wbr
実際に使用するのは、黄線のように高周波成分を削除した形の物を使用するわけです。

認識精度の確認

前回のコードに上記コードを追加し、以下のコードを修正します。赤線が変更箇所です。
ちなみに、y=0から1に変更したのは、g[0]に格納されているスケール係数を排除するためです。
追加
結果を見ると、上図が、変更前で下図が、変更後のチャートです。
※赤線:基本波形 ※黄色:一番近い過去の波形 ※白線:2・3番目に近い過去の線 です。
【変更前】
変更前

【変更後】
変更
使用した結果、1番近い過去の波形及び2番目と同じ波形を導いていますが、3番目の波形が異なることがわかります。(用いるデータが悪く変化がわかりづらい。。。orz)数値的には、悪くなっていますが、パターン認識の精度は、向上した、、、はずです。^^;

その他

3か月にわたり開催されたATC2011が修了しました。参加されたみなさん、お疲れ様でした。そして、応援して頂いた皆様、期待に応えられず申し訳ありません。今年は、第1週目にほぼ敗北宣言をするような結果になってしまいました。私の力量不足が招いた結果だと思っています。しかし、ATCへの参加は、面白いですよ^^;来年は、みなさんも参加されてはいかがでしょう?世界を相手に勝負できますよ(^o^)丿それでは、良いお年を!