見出し画像

自動売買システム日経225ミニ専用をC#で作る。ワンクリックで5個のアプリケーションを起動する。

自動売買システムを稼働するにはkabuステーションWebServer,nogrok,N225Trader,TradingViewの5アプリケーションを起動する必要があります。5回クリックすれば起動するので労力はいらない。でもkabuステーションのログインにはパスワードを入力する、ngrokはコマンドウインドウで「ngrok + 引数」の入力が必要です。この作業を毎日行い起動する。この作業を1クリックで行えればと考えランチャーを作成しました。

インストールと初期設定


1.ランチャーアプリのインストール
  デスクトップにランチャーアイコンが表示されます。
2・ランチャーアプリ起動
3.初期画面にユーザー名、kabuステーションのパスワード 
  設定する
4.自動売買システムを起動する場合はチェックボタンにチ
  ェックを入れる。チェックを入れない場合は自動売買シ
  ステムは起動しないでランチャーのみの機能になります

初期化画面

ランチャーに起動に必要なアプリケーションを登録


5つのアプリケーションのショートカットアイコンを左上からkabuステーション、WbServer,ngrok,N225Trader,
TradingViewの順にドラック&ドロップで貼り付ける。

必要のないショートカットアイコンはドラック&ドロップで
ゴミ箱に入れる。

4つアイコンスペースがあるので必要なアプリケーションを登録することができます。
以上の設定ができたら終了しランチャーアイコンをタスクバーおよびスタートにピン止めする。

Launcher

自動売買システムを稼働する

タスクバーまたはスタートからランチャーアイコンをクリックするとログインパスワードを自動設定し5つのアプリケーションは起動します。

ランチャーアプリは鳩でもわかるC# ランチャーアプリの作り方を参考にさせて。いただきました。

kabuステーションのログインパスワード設定ロジック

kabuステイションを起動すると下記のログインウインドウが描写されます。このパスワード欄にパスワードを入力しログインボタンをマウスでクリックする動作を自動で行います。

kabuステーションログイン画面

C#で他アプリケーショ操作するためには

Windowsの仕組みを理解する必要があります。
上記ログイン画面では
1.口座番号入力ボックス
2. パスワード入力ボックス
3. チェックボタン
4. ラジオボタン
5. ログインボタン
6. 終了ボタン
などの要素があるのがわかります。まだこの画面には沢山の要素が含まれています。これらの要素はすべて「ウインドウ」です。全てのウインドウには要素毎にIDが振られています。これは「ウインドウハンドル」と呼ばれています。

ログインウインドウのすべてのハンドルを取得する

ウインドウハンドルを取得するにはWindowsAPI、FindWindowEx関数などを使って探します。
win32 APIコード

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr ptr, StringBuilder lParam);

        /* ********* 親ウィンドウを検索する。親を持たないウインドウのハンドルを 返す */
        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        /* 子ウインドウのハンドルを取得する */
        [DllImport("user32.dll")]
        public static extern IntPtr FindWindowEx(IntPtr hWnd, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

        [DllImport("user32")]
        public static extern int GetWindowLong(IntPtr whnd, int nIndex);
        
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int GetWindowTextLength(IntPtr whnd);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int GetWindowText(IntPtr whnd, StringBuilder lpString, int nMaxCount);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern int GetClassName(IntPtr whnd, StringBuilder lpClassName, int nMaxCount);

        //画面サイズ取得用構造体
        [StructLayout(LayoutKind.Sequential)]
        private struct RECT
        {
            public int left;
            public int top;
            public int right;
            public int bottom;
        }

        //ウインドウサイズ取得API
        [DllImport("user32.dll")]
        private static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);
        //ウインドウサイズ取得API(精度が良い)
        [DllImport("dwmapi.dll")]

    private const uint WM_SETTEXT = 0x000C;               //文字列を送る
    private const int WM_LBUTTONDOWN = 0x201;            //マウス左ボタンdown
        private const int WM_LBUTTONUP = 0x202;              //左ボタンUP

ウインドウ検索メソッド

    private Window GetWindow(IntPtr whnd)
        {
            int textLen = GetWindowTextLength(whnd);
            string windowText = null;
            if (0 < textLen)
            {
                //ウィンドウのタイトルを取得する
                StringBuilder windowTextBuffer = new StringBuilder(textLen + 1);
                GetWindowText(whnd, windowTextBuffer, windowTextBuffer.Capacity);
                windowText = windowTextBuffer.ToString();
            }

            //ウィンドウのクラス名を取得する
            StringBuilder classNameBuffer = new StringBuilder(256);
            GetClassName(whnd, classNameBuffer, classNameBuffer.Capacity);

            // スタイルを取得する
            int style = GetWindowLong(whnd, GWL_STYLE);
            return new Window() { whnd = whnd, Title = windowText, ClassName = classNameBuffer.ToString(), Style = style };
        }

        /// <summary>
        /// 指定したウィンドウの全ての子孫ウィンドウを取得し、リストに追加する
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="dest"></param>
        /// <returns></returns>
        private List<Window> GetAllChildWindows(Window parent, List<Window> dest)
        {
            dest.Add(parent);
            EnumChildWindows(parent.whnd).ToList().ForEach(x => GetAllChildWindows(x, dest));
            return dest;
     }

    /// <summary>
        /// 与えた親ウィンドウの直下にある子ウィンドウを列挙する(孫ウィンドウは見つけてくれない)
        /// </summary>
        /// <param name="hParentWindow"></param>
        /// <returns></returns>
        private IEnumerable<Window> EnumChildWindows(IntPtr hParentWindow)
        {
            IntPtr hWnd = IntPtr.Zero;
            while ((hWnd = FindWindowEx(hParentWindow, hWnd, null, null)) != IntPtr.Zero) { yield return GetWindow(hWnd); }
         }

/// <summary>
    /// 子、孫 Windowの情報を格納する
    /// </summary>
    class Window
    {
        public string Cla ssName;
        public string Title;
        public I ntPtr whnd;
        public int Style;
    }
 

Login(string password) メソッド

1.ウィンドウ検索用メソッドを使ってログイン画面のすべて
  のWindowsハンドル、クラス名と座標をリストに取得保
  存する。
2. 取得したWindowリストからパスワード入力ボックスの 
  クラス名は「EDIT」を検索し(2つ存在する)座標top
  の大きい方をパスワード入力ボックスハンドルと確定す
  る。
3. ログインボタンは座標の位置関係から確定する。
4. パスワードはwin32 dll  SendMessage()メソッドにより
  パスワードボックスに書き込まれる。
5. ログインボタンをマウスでクリックする。
  このコードはマウスクリックダウン、マウスクリックア
  ップの2つの操作が必要です。この方法は、
  WM_LBUTTONDOWNをSendMessage()にセットしメッ
  セージを送る。
  WM_LBUTTONUPをSendMessage()にセットしメッセ 
  ージを送ることで実現できます。これでkabuステーショ
  ンのメイン画面が開きトレード開始の準備が出来まし
  た。
以下のコードがlogin()メソッドです。

    public bool Login(string password) 
        {
            bool result = false;
            //ログインウインドウのハンドル取得
            whndLogin = FindWindow(null, "ログイン");
            if (whndLogin != IntPtr.Zero)
            {
                string Password = password;
                RECT Krect;
                RECT Clrect;

                IntPtr Accounthwnd = IntPtr.Zero;
                IntPtr paswordhwnd = IntPtr.Zero;
                IntPtr loginhwnd = IntPtr.Zero;
                IntPtr endWhnd = IntPtr.Zero;
                IntPtr tmpWhnd = IntPtr.Zero;

                int top = 0;

                //ログインダイヤログのタイトル、クラス名、情報を取得する。
                Window loginInf = GetWindow(whndLogin);
                dest.Clear();
                //ログインウィンドウのハンドルすべてを列挙保存する
                dialogList = GetAllChildWindows(loginInf, dest);

                //全てのコントロール座標とクラス名をlocationListに再構築する
                foreach (Window win in dialogList)
                {
                    //全てのコントロール座標とクラス名
                    GetWindowRect(win.whnd, out Krect);
                    locationList.Add(new Location()
                    {
                        hwnd = win.whnd,
                        ClassName = win.ClassName,
                        left = Krect.left,
                        top = Krect.top,
                        right = Krect.right,
                        bottom = Krect.bottom
                    });

                }
                //locationListをtopをkeyにしてsortする(ラムダ式)
                locationList.Sort((a, b) => a.top - b.top);
                //口座番号、パスワードのハンドル取得
                foreach (Location lo in locationList)
                {
                    if (lo.ClassName.IndexOf("EDIT") >= 0)
                    {
                        if (top == 0)
                        {
                            top = lo.top;
                            tmpWhnd = lo.hwnd;
                        }
                        else
                        {
                            //大きい方がパスワードtextBox
                            if (top < lo.top)
                            {
                                paswordhwnd = lo.hwnd;
                                Accounthwnd = tmpWhnd;
                            }
                            else
                            {
                                paswordhwnd = tmpWhnd;
                                Accounthwnd = lo.hwnd;
                            }
                        }

                    }
                }
                //ログインボタン、終了ボタンのハンドル取得
                Location botton1 = locationList[locationList.Count - 1];
                Location botton2 = locationList[locationList.Count - 2];
                //leftの小さい方がログインボタン
                if (botton1.left < botton2.left)
                {
                    loginhwnd = botton1.hwnd;
                    endWhnd = botton2.hwnd;
                }
                else
                {
                    loginhwnd = botton2.hwnd;
                    endWhnd = botton1.hwnd;
                }

                //パスワードのtextBoxが特定できたのでパスワードを入力する
                if (paswordhwnd != IntPtr.Zero)
                {
                    StringBuilder sb = new StringBuilder(Password);
                    SendMessage(paswordhwnd, WM_SETTEXT, IntPtr.Zero, sb);
                    Thread.Sleep(1000);

                    // ログインボタンをマウスは押してから放す
                    SendMessage(loginhwnd, WM_LBUTTONDOWN, MK_LBUTTON, 0x000A000A);
                    SendMessage(loginhwnd, WM_LBUTTONUP, 0x00000000, 0x000A000A);

                }
                result = true;
            }
            else
            {
                result = false;
            }
            //p.EnableRaisingEvents = true;
            //p.Exited += P_Exited;
            return result;

        }

以上がランチャーのメイン部分です。概要だけの記事ですが
これでワンクリックで自動売買は開始できます。
この記事のアプリケーションに興味ある方はこのページの
一番下のクリエイターへのお問い合わせでご一報ください。

この記事が気に入ったらサポートをしてみませんか?