CFD完全自動売買 (解決編)

ここ数日続いてきました、表題の取り組みが一旦の解決をみました。

例の、CFD取引の日経先物225取引のイブニングセッションもどきの部分について、発注作業を完全自動化する目論みです。

 

ご参考までに、情報を載っけときます。

(動作に際し、保証はできませんのであしからず。また、VPS(Linux)の力も借り、サーバ2台による協調処理となります)

 

なんでこんなメンドクサイことをしているかというと、Windowsは、リモートデスクトップ接続中などのように、外部入力のトリガが存在しないと、プログラム処理による”マウスクリック”などのイベント処理が起こせない為、完全自動化を実現する為にこんなふうになってしまいました。

 

システム処理の流れ

  1. VPS (Linux)で、cronによりリモートデスクトップを時間起動
  2. リモートデスクトップアライブ中に、VPS(Windows Server 2012)でMAサイン225(オーバーナイト)の自動操作 (MAサイン起動➡自動マウスクリックで売買サイン判定➡MT4起動(EAが自動稼働するように仕込んでおきます))
  3. リモートデスクトップの自動切断
  4. Windows Server上のMT4をタイマー終了

 

力つきそうですので、ざっくりまとめます

 

1.VPS (Linux)でcronによりリモートデスクトップを時間起動

 

これは簡単ですね。

crontab -eで

29 15 * * 1-5 DISPLAY=:0 /home/xxx/rdesk.sh

でタイマー起動シェルを指定しておきます。上記の例では、月曜日から金曜日(1-5のところ)の、15:29にrdesk.shを起動する、となります。

このシェルスクリプトでは、rdesktopを使用しますので、X Windowの指定の必要があります。(DISPLAY=:0  のところ。これで、実画面に接続セッションがなくても、X Windowを利用するソフトが動いてしまいます。さすが、Linux)

 

rdesk.shのサンプル

#!/bin/sh 

# rdesktop 
/usr/bin/rdesktop -k ja "サーバのIPアドレスや接続子情報" -u "接続ユーザ" -p "接続ユーザのパスワード" -g 1600x900 & 

# wait 11分
sleep 660 

# rdesktopを終了する
isAlive=`ps -ef | grep rdesktop |grep -v grep | wc -l` 
if [ $isAlive = 1 ]; then 
  pidRdesk=`ps -ef | grep rdesktop |grep -v grep | awk '{ print $2; }'` 
  kill $pidRdesk 
else 
  echo "Oh!" 
fi 

echo "Task completed..."

 

Linux の処理はこんなもんで済みます。

 

さて、、、

 

2.リモートデスクトップアライブ中に、VPS(Windows Server 2012)でMAサイン225(オーバーナイト)の自動操作 (MAサイン起動➡自動マウスクリックで売買サイン判定➡MT4起動)

 

サンプルです。Webから引っぱりまくりました。感謝感謝。そしてちょっと複雑になりました。

それなりに詳しい方なら、どこを改造すればよいかは簡単かと思います。それなりに詳しくない方も、日本語の部分を拾って頂ければ、何をしているのか大体お分かりになるかと。

 

cfd.ps1 (Windows PowerShell Script)

# ウインドウ処理は、C#の力を借りる
$source = @"
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

public class MASign225 {

  private IntPtr hMASign225;

  public MASign225() {
    hMASign225 = IntPtr.Zero;
  }

  // マウス関連のWin32API
  [DllImport("user32.dll")]
  extern static uint SendInput(
    uint       nInputs,   // INPUT 構造体の数(イベント数)
    INPUT[]    pInputs,   // INPUT 構造体
    int        cbSize     // INPUT 構造体のサイズ
  );

  [StructLayout(LayoutKind.Sequential)]
  struct INPUT
  { 
    public int        type;
    public MOUSEINPUT mi;
  }

  [StructLayout(LayoutKind.Sequential)]
  struct MOUSEINPUT
      {
        public int    dx ;
        public int    dy ;
        public int    mouseData ;  // amount of wheel movement
        public int    dwFlags;
        public int    time;        // time stamp for the event
        public IntPtr dwExtraInfo;
    }

  const int MOUSEEVENTF_MOVED      = 0x0001 ;
  const int MOUSEEVENTF_LEFTDOWN   = 0x0002 ;  // 左ボタン Down
  const int MOUSEEVENTF_LEFTUP     = 0x0004 ;  // 左ボタン Up
  const int MOUSEEVENTF_ABSOLUTE   = 0x8000 ;

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    static extern int MoveWindow(IntPtr hwnd, int x, int y, int nWidth,int nHeight, int bRepaint);

    [System.Runtime.InteropServices.DllImport("user32.dll")]
     static extern bool SetForegroundWindow(IntPtr hWnd);

    public void startMASign225()  {

        System.Diagnostics.Process p = System.Diagnostics.Process.Start("C:\\Users\\UserAccount\\Documents\\MAサイン225 【2014版】\\MA2014  オーバーナイト  .exe");
        p.WaitForInputIdle();

        hMASign225 = p.MainWindowHandle;
        MoveWindow(hMASign225, 0, 0, 780, 640, 1);

        if (hMASign225 != IntPtr.Zero) {
            SetForegroundWindow(hMASign225);
        }

    }

    public void clickMASign225(int width, int height) {
      if (hMASign225 != IntPtr.Zero) {
          SetForegroundWindow(hMASign225);
          System.Threading.Thread.Sleep(1 * 1000);

          INPUT[] input = new INPUT[3];

          // 1.日経情報の取得のクリック
          input[0].mi.dx = 500 * (65535 / width);
          input[0].mi.dy = 150 * (65535 / height);
          input[0].mi.dwFlags = MOUSEEVENTF_MOVED | MOUSEEVENTF_ABSOLUTE;
          input[1].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
          input[2].mi.dwFlags = MOUSEEVENTF_LEFTUP;
          SendInput(3, input, Marshal.SizeOf(input[0]));

          System.Threading.Thread.Sleep(30 * 1000);

          // 2.サイン生成のクリック
          input[0].mi.dx = 600 * (65535 / width);
          input[0].mi.dy = 250 * (65535 / height);
          input[0].mi.dwFlags = MOUSEEVENTF_MOVED | MOUSEEVENTF_ABSOLUTE;
          input[1].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
          input[2].mi.dwFlags = MOUSEEVENTF_LEFTUP;
          SendInput(3, input, Marshal.SizeOf(input[0]));
      }
    }

    public void quitMASign225(int width, int height) {
      if (hMASign225 != IntPtr.Zero) {
          SetForegroundWindow(hMASign225);

          INPUT[] input = new INPUT[3];

          // 3.終了ボタンのクリック
          input[0].mi.dx = 680 * (65535 / width);
          input[0].mi.dy = 580 * (65535 / height);
          input[0].mi.dwFlags = MOUSEEVENTF_MOVED | MOUSEEVENTF_ABSOLUTE;
          input[1].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
          input[2].mi.dwFlags = MOUSEEVENTF_LEFTUP;
          SendInput(3, input, Marshal.SizeOf(input[0]));
      }
    }
}
"@

###################################################################
# ここからが実処理部分です
###################################################################

# 既にMAサインのオーバナイト版が起動済みなら、一度MAサインを終了する    
Stop-Process -Name "MA2014  オーバーナイト  " -errorAction silentlyContinue
Start-Sleep -s 10;

# 重複実行の防止機構
$da = Get-Date;
$todayStr = $da.ToString("yyyyMMdd");
$todayStr = $todayStr -as [System.String];
Write-Output $todayStr;

$lockFile = "C:\Users\UserAccount\OneDrive\MASign225\" + $todayStr + ".lock";
if ( Test-Path $lockFile) {
  echo $lockFile;
  echo "file exists";
  return;
} else {
  New-Item $lockFile -itemType File;
}

# 画面サイズを取得する
[Void][Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[Void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")    
[System.Windows.Forms.Screen] $screen = [System.Windows.Forms.Screen]::PrimaryScreen;
[System.Drawing.Rectangle] $rect = $screen.Bounds;
$screenWidth  = $rect.Width;
$screenHeight = $rect.Height;

echo " "
echo "-- Screen Size --"
echo $rect.Width;
echo $rect.Height;
echo " "

# MASign225 のハンドラ
Add-Type -Language CSharp -TypeDefinition $source -ReferencedAssemblies System.Windows.Forms
$masign = New-Object -TypeName MASign225;

# MAサイン225を起動する
$masign.startMASign225();
Start-Sleep -s 10;

# MAサイン225でサイン生成プロセスを実行する
$masign.clickMASign225($screenWidth, $screenHeight);
Start-Sleep -s 5;

# サインを画面キャプチャする
$capFile = "C:\Users\UserAccount\Documents\sign.bmp"

# 古いファイルを削除する
Remove-Item $capFile  -errorAction silentlyContinue
Start-Sleep -s 3;    

$capWidth = 210 
$capHeight = 75
$capX = 500 
$capY = 375 

# 準備:BitmapオブジェクトからGraphicsオブジェクトを作成    
$bmp = New-Object System.Drawing.Bitmap($capWidth, $capHeight);
$gfx = [System.Drawing.Graphics]::FromImage($bmp);

# スクリーンショットを取得 MASign225のサインのところ
$gfx.CopyFromScreen($capX, $capY, 0, 0, $bmp.Size);

# 画像ファイルを保存
$bmp.Save($capFile);

# MD5ハッシュ値を計算する
$md5Obj = [System.Security.Cryptography.MD5]::Create();

$stream = New-Object IO.StreamReader $capFile;
$hash = $md5Obj.ComputeHash($stream.BaseStream);

$md5sum = [System.BitConverter]::ToString($hash).ToLower().Replace("-","");

# MAサイン225の実行を終了する
$masign.quitMASign225($screenWidth, $screenHeight);

echo " "
echo "-- Sign MD5 --"
Write-Output $md5sum
echo " "

$signLong  = "ここは、ディスプレイの設定により変動もします";
$signShort = "abc";

$mt4p = -1;

switch ($md5sum) {

  $signLong {
    echo " "
    echo "--------------------"
    echo "   買いサインです!!";
    echo "--------------------"
    echo " "

    $mt4p = (Start-Process -FilePath "C:\Program Files (x86)\XM MT4  - CFDTESTLONG\terminal.exe" -PassThru).id
    Start-Sleep -s 30;
  }
  $signShort {
    echo " "
    echo "--------------------"
    echo "   売りサインです!!";
    echo "--------------------"
    echo " "

    # 売り専用のMT4を起動しましょう。。。
  }
  default {
    echo "!!!!!!!!!!!!!!!!!!!!!!!!"
    echo " トレードを見送ります..."
  }
}

# MT4終了予定時刻   MT4を終了したい時間を設定しましょう (何時から何時の間に、みたいな)
$mt4terminateBegin = 0;
$mt4terminateEnd   = 2500;

# このシェルから起動したMT4を終了する
if ($mt4p -ne -1) {
    do {
      $now = Get-Date -format HHmm 
      $now = $now -as [System.Int32]

      if (($now -ge $mt4terminateBegin) -and ($now -le $mt4terminateEnd)) {
          Stop-Process $mt4p;
          Start-Sleep -s 10;    
          break;
      } else {
          echo $now
          echo 'waiting,,, '
          Start-Sleep -s 60;
      }
    } while ($true)
}

 

という具合の処理となります。このサンプルの実行構造を改造し、パワーシェルを常時稼働するように組んでおけば、オーバナイトセッションの売買の完全自動化ができるというわけでござります。

 

PowerShell初めて書いたけど、C#のクラス定義ができたり、凄いねまたごっちゃごっちゃしてて。

 

 

3 thoughts on “CFD完全自動売買 (解決編)

  1. 日経225とドル円をCFDで取引できればいいのに どうも2銘柄のEAが見当たりません。
    前日値幅の中で4時半に取引 当日3時決済ができればEAとインジをお願いしたいです。

  2. 私はプログラムができませんが、
    MT4によるEAに取り組んできておられる蓄積とご苦労はお察ししました。
    ところで、ご回答による設定は、VPSを起動→MT4を起動 (MT4のEAとインジは、読み込んだ前日の高安と値幅の反映と自動計算ができますか。
    ロジックは時間指定によるMA CCI ATRによるサイン表示とIFOによる発注と決済) 以上について取り組まれた場合の料金を見積もってください。
    よろしくお願いします。

    1. tasukeさん、初めまして。

      お返事が遅くなり、申し訳ございません。

      頂いたコメント内容は、最終的には日経225等を対象とした、”EAの作成依頼”と受け止めております。
      こちらに関しては、当方が未熟である為、ご希望にお応えすることができません。誠に申し訳ございません。

      ご希望されているものは、最終的には作成可能ではあると思います。しかしながら、私はMT4のプログラム作成スキルは、殆どありません。
      単純な挙動をするものは製作できますが、インジと組み合わせたりしたプログラムは、ご納得いただけるレベルのもが直ぐに作れませんし、品質を保証するノウハウやより良いご提案をするスキルも持ち合わせておりません。

      誠におこがましいのですが、例えばfx-onさんのクラウドソーシングや、実績を残したEAをリリースされている販社さんのEA作成サービスを利用なさっては如何でしょうか。
      恐らく、ご所望のものを手に入れるのに、より良い選択の一つではないかと存じます。

      せっかくこのようなお話を頂いたのに、申し訳ございません。

      今後とも良いお付き合いが出来れば、幸甚でございます。

コメントを残す