/// <summary> /// もし404エラー(接続切れ)になっていたらログインを再度行う /// </summary> public void RetryLogin() { try { // エラーになっていないかどうか確認 見つかった場合は何もしない this.IsActivate(); if (this.chrome.IsFindElementById("header")) { return; } // 見つからない場合はログインしなおし TODO:デモと本番の切り替えられるようにする chrome.Navigate().Refresh(); chrome.WaitCompleteDelay(1000); // 歓迎ボタンを押す IWebElement welcomeBtn = CommonDriverControl. GetSafeWebElementByXPath(this.chrome, Constants.XPATH_HL_Welcome_Button); welcomeBtn.Click(); CommonControl.SleepWait(1000); CommonControl.DebugPrint("リフレッシュした。"); } catch (Exception e) { CommonControl.DebugPrint(e, "RetryLogin"); } }
/// <summary> /// ページが完全になるまで待つ /// 指定なし10分 /// </summary> /// <param name="waitMilliSeconds">待つ最大ミリ秒数</param> /// <returns>True:OK False:指定秒数までに待てなかった Exception:想定外の例外</returns> public Boolean WaitComplete(int waitMilliSeconds = 600000) { Boolean ret = false; DateTime endTime = DateTime.Now.AddMilliseconds(waitMilliSeconds); try { // 時間が過ぎるか、ステータスがTRUE while (!ret) { string state = (string)base.ExecuteScript("return document.readyState"); ret = state.Equals("complete"); if (!(DateTime.Now > endTime)) { throw new TimeoutException(); } } ; } catch (TimeoutException e) { TimeoutException IgnoreException = e; //CommonControl.DebugPrint(e, "ページが完全に読み込めませんでした"); } catch (Exception e) { //タイムアウト以外の例外 CommonControl.DebugPrint(e, "想定外の例外"); //throw e; } return(ret); }
/// <summary> /// 【シグナルメッセージ専用】 /// 対象の部屋にメッセージを書き込む /// </summary> /// <param name="toWriteRoomName">書き込む対象の部屋名</param> /// <param name="signalRoomName">実際に来たシグナルの部屋</param> /// <param name="argMsg">メッセージ</param> public void putSignalMsgToRoom(string toWriteRoomName, string signalRoomName, string argMsg) { try { // LINEをアクティブに this.chrome.SwitchWindowLine(); // 対象の部屋をアクティブに RoomAvtive(toWriteRoomName); // メッセージを書き込む IWebElement msgInputTxtBox = this.chrome.FindElementById("_chat_room_input"); msgInputTxtBox.Click(); // フォーカスあてる代わり //CommonControl.SleepWait(2000); msgInputTxtBox.SendKeys(signalRoomName); System.Windows.Forms.SendKeys.SendWait("+~"); // Shift + Enter string[] aryMsg = argMsg.Split(new string[] { Constants.LINE_CRLF }, StringSplitOptions.None); for (int i = 0; i < aryMsg.Length; i++) { msgInputTxtBox.SendKeys(aryMsg[i]); System.Windows.Forms.SendKeys.SendWait("+~"); // Shift + Enter } CommonControl.SleepWait(500); msgInputTxtBox.SendKeys(Keys.Enter); // 送信 } catch (Exception e) { CommonControl.DebugPrint(e, "メッセージの送信に失敗しました"); } }
/// <summary> /// 入札結果をライン用に整える /// </summary> /// <param name="msg">結果メッセージ</param> /// <returns></returns> public static string PrepareResultMessage(string msg) { string ret = string.Empty; try { String[] tmp = msg.Split(new string[] { "\r\n" }, StringSplitOptions.None); String[] tmpSub = tmp[2].Split(new string[] { " " }, StringSplitOptions.None); // 勝ち負け判定 string result = ""; try { // 2文字(\0)以上? result = tmpSub[5].Length > 2 ? "[WIN]" : "[LOSE]"; } catch { result = "[UNKOWN]"; } ret = "【入札結果】" + result; ret += " 通貨ペア:" + tmp[0]; ret += " / 入札レート:" + tmp[1]; if (tmp.Count() > 2) { if (tmpSub.Count() > 0) { ret += " / 入札時間:" + tmpSub[0]; } if (tmpSub.Count() > 1) { ret += " / 判定時間:" + tmpSub[1]; } if (tmpSub.Count() > 2) { ret += " / ステータス:" + tmpSub[2]; } if (tmpSub.Count() > 3) { ret += " / 判定レート:" + tmpSub[3]; } if (tmpSub.Count() > 4) { ret += " / 入札金額:" + tmpSub[4]; } if (tmpSub.Count() > 5) { ret += " / ペイアウト:" + tmpSub[5]; } } } catch (Exception e) { CommonControl.DebugPrint(e, "結果メッセージの出力に失敗 メッセージ" + msg); } return(ret); }
/// <summary> /// 部屋リストを最後までスクロールする /// </summary> /// <returns></returns> public Boolean ChatRoomListScrollEnd() { try { // スクロール this.chrome.ExecuteScript(string.Format("document.getElementById('{0}').scrollTop = document.getElementById('{0}').scrollHeight;", Constants.HTML_ID_LINE_ChatRoomDivId)); } catch (Exception e) { CommonControl.DebugPrint(e, "ChatRoomListScrollEnd"); throw e; } return(true); }
/// <summary> /// 平文のシグナル文章を各パラメータに解析する /// </summary> /// <param name="roomName">受けた部屋名</param> /// <param name="argSignalFlatWord">何れかのシグナル文章</param> /// <returns></returns> public static SignalOrder AnalysisWord(string roomName, string argSignalFlatWord) { SignalOrder ret = new SignalOrder(); try { switch (roomName) { case Constants.ROOM_NAME_AUXESIS: // AUXESIS用 ret = AnalysisByAuxesisMsg(argSignalFlatWord); break; case Constants.ROOM_NAME_RISE: // RISE用未作成 //ret = new SignalOrder(); break; case Constants.ROOM_NAME_CmdLine: case Constants.ROOM_NAME_SignalMeijin: ret = AnalysisBySignalMeijin(argSignalFlatWord); break; case Constants.ROOM_NAME_MIYU: ret = AnalysisByMiyuMsg(argSignalFlatWord); break; case Constants.ROOM_NAME_DebugRoomName: //debug用 ret = AnalysisByAuxesisMsg(argSignalFlatWord); break; } } catch (Exception e) { // シグナル解析に失敗した // throwしない CommonControl.DebugPrint(e); } finally { // 終わった後に格納 ret.signalRoomName = roomName; // 部屋名 ret.rawOriginalMessage = argSignalFlatWord; // メッセージ原文 } return(ret); }
/// <summary> /// 対象のルームをアクティブにする /// </summary> /// <param name="roomName">部屋名</param> public void RoomAvtive(string roomName) { try { bool successFlag = false; int tryTimes = 0; // 試行回数 while (successFlag == false) { // 部屋を画面内に IWebElement eleRoom = FindElementRoomTitleLiByXPath(roomName); CommonDriverControl.ScrollTargetElementView(eleRoom); // 部屋をクリックする eleRoom.Click(); this.chrome.WaitCompleteDelay(500); // 本当にクリック成功したか? IWebElement eleRoomHeader = this.chrome.FindElementByXPath("//*[@id='_chat_header_area']/div/div[2]/h1"); if (eleRoomHeader.Text.Equals(roomName)) { successFlag = true; } else { tryTimes += 1; } if (tryTimes >= 3) { throw new Exception("LINEの対象の部屋をアクティブにする既定の試行回数をこえました"); } } } catch (NoSuchElementException) { CommonControl.DebugPrint("対象の部屋をアクティブにしようとして失敗しました。 対象の部屋:" + roomName); throw; } catch (Exception e) { CommonControl.DebugPrint(e); //throw e; } }
/// <summary> /// 入札結果を取得し、終了のものが有れば、 /// エントリーしたシグナル情報と照らし合わせて /// どのシグナルでエントリーしたものかをチェックして /// 格納する /// </summary> /// <returns></returns> public void getSignalResult(ref List <BoHistroyContainer> boHistroyContainers) { try { IsActivate(); // ハイロー画面へ // リストを取得 IReadOnlyCollection <IWebElement> resultList = this.chrome.FindElementsByXPath("//*[@id='tradeActionsTableBody']/tr"); for (int i = 0; i < resultList.Count(); i++) { // 取引終了の結果があった場合 if (resultList.ElementAt(i).Text.Contains("取引終了")) { // 比較先 型を取る SignalResult resSig = CommonControl.ConvBoResult(resultList.ElementAt(i).Text); // すべての履歴コンテナと比較 for (int n = 0; n < boHistroyContainers.Count; n++) { // 比較元 入力シグナルコンテナ BoHistroyContainer bhc = boHistroyContainers.ElementAt(n); if (bhc.State != HistoryState.hsWaitResult) { continue; // シグナル結果待ちのもののみ比較対象とする } // 入札銘柄と時間が同じなら そのシグナルで入札した結果とし、googleに送信する if (resSig.R_TradeBrand.Equals(bhc.Sig.tradeBrand) && DateTime.Parse(resSig.R_JudgeTime).Equals(DateTime.Parse(bhc.Sig.tradeTimeFrame))) { boHistroyContainers.ElementAt(n).ResultSig = resSig; boHistroyContainers.ElementAt(n).State = HistoryState.hsWaitPost; // → Google送信待ち break; } } } } } catch (Exception e) { CommonControl.DebugPrint(e); } }
/// <summary> /// 新着メッセージの数を取得する /// </summary> /// <param name="roomName"></param> /// <returns></returns> public int getRoomNewArrivalsMsgNumber(string roomName) { // 対象のルームの新着番号 XPATH string targetRoomXPATH = string.Format(Constants.XPATH_LINE_NewArrivals, roomName); IWebElement ele = null; try { IsActivate(); // 要素が見つかったら if (chrome.FindElementsByXPath(targetRoomXPATH).Count > 0) { ele = chrome.FindElementByXPath(targetRoomXPATH); // 新着数 取得 if (string.IsNullOrEmpty(ele.Text.Trim(' '))) { return(0); } else { return(int.Parse(ele.Text.Trim(' '))); } } else { return(0); } } catch (Exception e) { if (ele != null) { CommonControl.DebugPrint(e, ele.Text); // 原因究明用 } else { CommonControl.DebugPrint(e); } return(0); } }
/// <summary> /// 【ID版】 /// 対象の要素が取得できる状態になってから /// 安全に取得する /// </summary> /// <param name="chrome">ドライバ</param> /// <param name="elementId"></param> /// <returns></returns> public static IWebElement GetSafeWebElementById(ChromeDriverEx chrome, string elementId) { try { IWebElement element; WaitElementArrivalById(chrome, elementId); element = chrome.FindElementById(elementId); return(element); } catch (Exception e) { CommonControl.DebugPrint(e); } // error return(null); }
/// <summary> /// MIYU 部屋用 /// /// メッセージ例:[IFTTT] EURUSD Low Chance ・・・ /// </summary> /// <param name="argSignalWord">解析する文章</param> /// <returns></returns> private static SignalOrder AnalysisByMiyuMsg(string argSignalWord) { SignalOrder Sio = new SignalOrder(); try { string[] tmp = argSignalWord.Split(new string[] { "\r\n" }, StringSplitOptions.None); string[] wword = tmp[0].Split(new string[] { " " }, StringSplitOptions.None); // 6文字の場合は間にスラッシュ if (wword[1].Trim().Length == 6) { char[] tmpBrand = wword[1].Trim().ToCharArray(); for (int n = 0; n < tmpBrand.Length; n++) { Sio.tradeBrand += tmpBrand[n]; if (2 == n) { Sio.tradeBrand += "/"; } } } // ハイかローを決める Sio.arrow = wword[2].Trim().Equals("High") ? arrowState.asHigh : arrowState.asLow; // 現在時間で次のエントリー時間を求める Sio.signalMsgTimeRceived = DateTime.Now; getNextEntryTime(Sio); //無条件 エントリーを指定 Sio.mainState = SignalState.soEntry; } catch (Exception e) { CommonControl.DebugPrint(e, "想定外のメッセージ形式"); Sio.mainState = SignalState.soInitilized; //throw; } return(Sio); }
/// <summary> /// 【正規版】本番にログインを行う /// </summary> public void Login() { try { //// ログインボタンを押す IWebElement loginBtn = CommonDriverControl.GetSafeWebElementByXPath( this.chrome, "//*[@id='header']/div/div/div/div/div/span/span/a[2]"); loginBtn.Click(); // ログイン後、ロードが走る場合があるのでそれを考慮 CommonControl.SleepWait(2000); // ログインID IWebElement eleLoginId = CommonDriverControl. GetSafeWebElementById(this.chrome, "login-username"); eleLoginId.SendKeys(Constants.Login_HL_ID); CommonControl.SleepWait(500); // ログインパスワード IWebElement eleLoginPassWord = CommonDriverControl. GetSafeWebElementById(this.chrome, "login-password"); eleLoginPassWord.SendKeys(Constants.Login_HL_PassWord); CommonControl.SleepWait(500); // なんかログインボタンがうまく取れないのでエンターで代用 eleLoginPassWord.SendKeys("\r\n"); //// ログインボタン 押下 //IWebElement eleLoginTriggerBtn = CommonDriverControl. // GetSafeWebElementByXPath(this.chrome, "//*[@id='signin - popup']/div[1]/div/div[2]/div[1]/form/div/div[6]"); //eleLoginTriggerBtn.Click(); } catch (Exception e) { // 何らかの原因でログインに失敗した CommonControl.DebugPrint(e, "HighLow Login"); throw; } }
/// <summary> /// 次にエントリーする時間を求める /// </summary> /// <param name="argSio">シグナル情報</param> /// <returns></returns> private static void getNextEntryTime(SignalOrder argSio) { try { // エントリー時間 int entryHour = 0; // 時 int entryMinute = 0; // 分 // シグナルメッセージ時刻 DateTime sTime = argSio.signalMsgTimeRceived; // 次の5分刻みの時刻をもとめる entryHour = sTime.Hour; entryMinute = sTime.Minute; entryMinute = entryMinute + 5 - (entryMinute % 5); // 次の時間またいでいるとき Hour繰り上げ if (entryMinute >= 60) { entryHour = entryHour + 1; entryMinute = entryMinute % 60; } // エントリー時間 TODO:Parseがミスする? argSio.tradeEntryTime = DateTime.Parse(entryHour.ToString() + ":" + entryMinute.ToString() + ":00"); // タイムフレーム時間 エントリー時間の5分後 DateTime fTime = argSio.tradeEntryTime.AddMinutes(5); argSio.tradeTimeFrame = fTime.Hour.ToString("00") + ":" + fTime.Minute.ToString("00"); } catch (Exception e) { // CommonControl.DebugPrint(e, "次のエントリー時間を求めるのに失敗した" + argSio.lineSignalTimeRceived); throw; } }
static void Main(string[] args) { //ForDebugOnly(); // デバッグ用関数 //return; try { // ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== // 起動準備 & 引数用意 // ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== ===== // パラメータ設定の初期化(取得) Constants.Initialize(); // ブラウザ立ち上げ ChromeDriverEx chrome = CreateNewChromeDriver(); // 経済指標を取得 //InvestingCalender InvC = new InvestingCalender(ref chrome); //InvC.GetInvestingCalender(); //// LINE用 LINEControl cLINE = new LINEControl(ref chrome); // ログイン ライン cLINE.LoginLINE(); //// 初回ログイン時はログイン情報だけを記憶させて終了 //if (Constants.Login_Line_First) return; //// highlow 本トレ HighLowControl cHighLow_Real = new HighLowControl(ref chrome); cHighLow_Real.Open(false); // 本番OPEN cHighLow_Real.Login(); // 本トレログイン ///// highlowデモ HighLowControl cHighLow_Demo = new HighLowControl(ref chrome); cHighLow_Demo.Open(true); // デモOPEN cHighLow_Demo.demoLogin(); // デモログイン CommonControl.SleepWait(500); // ユーザーによるコマンド受付 情報保持用 string userCommandStatus = string.Empty; //ハイロー入札履歴 List <BoHistroyContainer> HL_History = new List <BoHistroyContainer>(); #if DEBUG //ForDebugOnly(chrome); //return; #endif // シグナルが来るまで待つか、[コマンド]終了を受け付けたら終了 while (true) { //CommonControl.DebugPrint("待機開始・・・"); // メッセージを待つ string signalRoomName = WaitLineGroupsNewArraival(cLINE); // なければ、終了定期処理へ if (string.IsNullOrEmpty(signalRoomName)) { CommonControl.DebugPrint("この時間来ませんでした" + DateTime.Now); goto finallyProcess; // 終了まで飛ばす } // 以下、シグナル受信していたら // メッセージが来た時 // 新着対象の部屋のメッセージ群を取得する ArrayList newMsgList = cLINE.getNewMsgText(signalRoomName); // メッセージがあるか?(通知に気づいたときには古いメッセージしかなくて新着メッセージないときは抜ける) if (newMsgList.Count == 0) { // 新着に気づいたが、メッセージが古い時間のものしか無かった時 CommonControl.DebugPrint("気づくのが遅かった・・・部屋名:" + signalRoomName); goto finallyProcess; // 終了まで飛ばす } string newMsg = ""; if (!userCommandStatus.Equals("stop")) { // エントリーの情報1つのみに絞り込むか又は命令メッセージ(最初に見つかったエントリー メッセージを取得) newMsg = HighLowControl.SelectSignalMsg(signalRoomName, newMsgList); } else { newMsg = (string)newMsgList[newMsgList.Count - 1]; } if (Constants.LINE_RECEIVER_SIDE) { // 子機の場合は冒頭についているどの部屋から来たか情報を取り出し // メッセージの冒頭の親からのヘッダパラメータをカットしてシグナル文のみにする signalRoomName = HighLowControl.AnalysisReceiverSide(ref newMsg); } // ※Stop時以外 // 命令かバイナリー配信かを判断する if (IsSignalMsg(signalRoomName, newMsg)) { // バイナリー配信の時 // 親機の時のみ if (Constants.LINE_RECEIVER_SIDE == false) { // 対象の部屋(グループ)へメッセージをコピー cLINE.putSignalMsgToRoom(Constants.ROOM_NAME_BoSignal, signalRoomName, newMsg); } // シグナル解析 SignalOrder sig = HighLowControl.AnalysisWord(signalRoomName, newMsg); // 指標の高い重要度の時間帯でないか\ // 又は、指定した時間帯 //if (!InvC.JudgeEnvironmentSignalZone(ref sig, ref cLINE)) //sig.Environment = EnvState.esTest; // 無条件デモ HighLowControl.JudgeRealDemo(ref sig); // エントリー結果 bool entryResult = false; if (sig.Environment.Equals(EnvState.esReal)) { // リアルトレード entryResult = cHighLow_Real.EntryHighLow(ref sig); } else { // デモトレード entryResult = cHighLow_Demo.EntryHighLow(ref sig); } // 結果をラインに表示 if (entryResult) { //成功時 cLINE.putSignalMsgToRoom(Constants.ROOM_NAME_CmdLine, signalRoomName, "エントリーに成功。" + Constants.LINE_CRLF + sig.getEntryNoticeMsg()); // シグナル履歴にストック BoHistroyContainer boc = new BoHistroyContainer(HistoryState.hsWaitResult, sig); HL_History.Add(boc); } else { CommonControl.DebugPrint("エントリーに失敗。" + sig.rawOriginalMessage); // デバッグ用 //cLINE.putSignalMsgToRoom(Constants.ROOM_NAME_CmdLine, signalRoomName, "エントリーに失敗。" + sig.rawOriginalMessage); } // 待機に戻る } else { // バイナリー配信ではなくて、命令の時 ステータスにセット if (signalRoomName.Equals(Constants.ROOM_NAME_CmdLine)) // 命令は指定のルームからのメッセージのみ受け取る { // 命令の抽出 string comResult = CommandProc(newMsg, userCommandStatus, out userCommandStatus); // エラーがあった場合 if (comResult.Length != 0) { cLINE.putSignalMsgToRoom(Constants.ROOM_NAME_CmdLine, "", comResult); } // 命令実行 TODO:今は仮 if (userCommandStatus.IndexOf("end") >= 0) // 終了時 { cLINE.putSignalMsgToRoom(Constants.ROOM_NAME_CmdLine, signalRoomName, "プログラムを終了します。" + newMsg); break; } } } // 1通り終了時 定期的に行う処理 finallyProcess: // ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- // 溜まったタスクを消化 // ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- System.Windows.Forms.Application.DoEvents(); ClickActionTrigger += 1; // ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- // 結果を見に行き、新着があればそれを部屋に出力 // ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- cHighLow_Real.getSignalResult(ref HL_History); // 本トレ cHighLow_Demo.getSignalResult(ref HL_History); // デモ それぞれに見に行く for (int i = 0; i < HL_History.Count; i++) { if (HL_History[i].State == HistoryState.hsDone) { continue; // 全て完了済みのものは飛ばす } bool ret = false; HL_History[i].PostResultData = CommonControl.PostBoResult(HL_History[i]); // Google送信 // postデータが作られていたら成功 HL_History[i].State = string.IsNullOrEmpty(HL_History[i].PostResultData) ? HL_History[i].State : HistoryState.hsPostDataComplete; // 成功したかどうか ret = CommonControl.OutPutTextBoResult(HL_History[i]); // テキスト吐き出し // テキスト掃き出しできたらすべて完了 HL_History[i].State = ret ? HistoryState.hsDone : HL_History[i].State; } // TODO: コンプリートしたBOコンテナ要素はここで削除しても良いかも // ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- // 2minに一回何らかのアクションを起こしてメッセージの受信頻度を上げる // スリープ(LINE受信しなくなる)対策 // ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- if (ClickActionTrigger % 2 == 0) { CommonControl.ClickAction(); ClickActionTrigger = 0; // 受信が行われるようにActiveWindowsの切り替えを行う //TODO:実験成功? 画面のライトがONOFFしなくても受信できるかチェックする SendKeys.SendWait("%{TAB}"); CommonControl.SleepWait(500); SendKeys.SendWait("%{TAB}"); // ネットワークが切れていれば 再ログイン 効果未確認 cHighLow_Real.RetryLogin(); } // debug用 //break; } // main end // ハイローログアウト //cHighLow_Demo.Logout(); //cHighLow_Real.Logout(); chrome.Quit(); } catch (Exception e) { // 想定外エラー発生時 // 原因調査用 CommonControl.DebugPrint(e, "Main Exception"); } finally { CommonControl.DebugPrint("プログラムを終了しました"); } }
/// <summary> /// アクシス部屋の文章を解析する /// 以下は1マーチンメッセージ例 上から下へ受信する /// [バイナリー配信] Mon Jan 07 2019 16:59:00 待機,,EURUSD,5分,ロー,数値:1.144 /// [バイナリー配信] Mon Jan 07 2019 16:59:53 エントリー,ptn20,EURUSD,5分,ロー,数値:1.144 /// [バイナリー配信] Mon Jan 07 2019 17:04:36 待機,マーチン,EURUSD,5分,ロー,数値:1.144 /// [バイナリー配信] Mon Jan 07 2019 17:04:59 エントリー,マーチン,EURUSD,5分,ロー,数値:1.144 /// [バイナリー配信] Mon Jan 07 2019 17:10:00 ProPirot_WIN,EURUSD,5分,ロー,マーチン,CloseValue[1]:1.1435700 /// </summary> /// <param name="argWord">メッセージ平文</param> /// <returns></returns> private static SignalOrder AnalysisByAuxesisMsg(string argWord) { SignalOrder Sio = new SignalOrder(); try { // 受け取った時間 Sio.lineSignalTimeRceived = DateTime.Now; string[] signalArray = argWord.Split(','); string[] tmp; for (int i = 0; i < signalArray.Count(); i++) { switch (i) { case 0: // TODO:区切り文字を何にするか 今後の課題 string[] rep = { " 2020 " }; tmp = signalArray[i].Split(rep, StringSplitOptions.None); // Hawkの前 シグナルを受けた時間 とステータス String[] splitTimeAndState = tmp[1].Split(new string[] { " " }, StringSplitOptions.None); // 時間だけでよい 2019/03/07 受けた時間に修正する Sio.signalMsgTimeRceived = DateTime.Now; // DateTime.Parse(splitTimeAndState[0]); // エントリー時間関係の情報を計算する getNextEntryTime(Sio); // ステータス switch (splitTimeAndState[1].Trim()) { case "キャンセル": Sio.mainState = SignalState.soCancel; break; case "待機": Sio.mainState = SignalState.soEntry; // 待機をエントリーとして扱う break; case "エントリー": Sio.mainState = SignalState.soCancel; // エントリーメッセージが来た時点では既に遅いのでキャンセルにする break; case "WIN": Sio.mainState = SignalState.soResult; Sio.subState = SignalState.soWin; break; case "LOSE": Sio.mainState = SignalState.soResult; Sio.subState = SignalState.soLose; break; } break; // 1番目以外 default: // ptn20 if (signalArray[i].Equals("ptn20")) { Sio.subState = SignalState.soPtn20; } // マーチン else if (signalArray[i].Equals("マーチン")) { Sio.subState = SignalState.soMartin; } else { // 銘柄 if (string.IsNullOrEmpty(Sio.tradeBrand)) { // 6文字の場合は間にスラッシュ if (signalArray[i].Trim().Length == 6) { char[] tmpBrand = signalArray[i].Trim().ToCharArray(); for (int n = 0; n < tmpBrand.Length; n++) { Sio.tradeBrand += tmpBrand[n]; if (n == 2) { Sio.tradeBrand += "/"; } } } else { // それ以外 Sio.tradeBrand = signalArray[i].Trim(); } } // 入札時間 else if (string.IsNullOrEmpty(Sio.tradeTimeSpan)) { Sio.tradeTimeSpan = signalArray[i].Trim(); } // ハイロー else if (Sio.arrow == arrowState.asUnkown) { Sio.arrow = signalArray[i].Trim().Equals("ハイ") ? arrowState.asHigh : arrowState.asLow; } // 入札数値 else if (string.IsNullOrEmpty(Sio.bidPrice)) { // 数値の文字が入ってたら取得する if (signalArray[i].Contains("数値")) { try { Sio.bidPrice = signalArray[i].Split(':')[1]; } catch (Exception) { // 無視する //throw; } } } } break; } } Sio.signalCompleteFlag = true; } catch (Exception ex) { CommonControl.DebugPrint(ex, "想定外のメッセージ配列を受信しました。\nメッセージ:" + argWord); throw; } return(Sio); }
/// <summary> /// シグナル名人のシグナルを解析する /// </summary> /// <param name="argSignalWord"></param> /// <returns></returns> private static SignalOrder AnalysisBySignalMeijin(string argSignalWord) { SignalOrder Sio = new SignalOrder(); Sio.rawOriginalMessage = argSignalWord; string wTime; try { string[] tmp = argSignalWord.Split(new string[] { Constants.LINE_CRLF }, StringSplitOptions.None); for (int i = 0; i < tmp.Length; i++) { switch (i) { case 2: // 銘柄 char[] tmpBrand = tmp[i].Trim().ToCharArray(); for (int n = 0; n < tmpBrand.Length; n++) { Sio.tradeBrand += tmpBrand[n]; if (n == 2) { Sio.tradeBrand += "/"; } } break; case 3: // 取引時間 wTime = tmp[i].Split(new string[] { " " }, StringSplitOptions.None)[1]; Sio.tradeEntryTime = DateTime.Parse(wTime); if (wTime.Equals("0時0分")) { Sio.tradeEntryTime.AddDays(1); // 0時0分の時の入札は明日 } break; case 4: // 判定時間 wTime = tmp[i].Split(new string[] { " " }, StringSplitOptions.None)[1]; DateTime dt = DateTime.Parse(wTime); wTime = dt.Hour.ToString("00") + ":" + dt.Minute.ToString("00"); Sio.tradeTimeFrame = wTime; break; case 5: // ハイロー Sio.arrow = tmp[i].Trim().Equals("Low") ? arrowState.asLow : arrowState.asHigh; break; case 6: // 指標値 Sio.bidPriceRawMessage = tmp[i]; Sio.bidPrice = tmp[i].Split(new string[] { " " }, StringSplitOptions.None)[0]; break; case 7: if (tmp[i].Equals("エントリー準備です")) { Sio.mainState = SignalState.soEntry; // エントリー行う } else { Sio.mainState = SignalState.soInitilized; // それ以外は無視 } break; default: break; } } } catch (Exception e) { CommonControl.DebugPrint(e, "想定外の形式メッセージが来た"); } return(Sio); }
/// <summary> /// 対象の部屋のメッセージの最新テキストを取得 /// </summary> /// <param name="roomName">部屋名</param> /// <returns></returns> public ArrayList getNewMsgText(string roomName) { ArrayList rceMsgs = new ArrayList(); IReadOnlyCollection <IWebElement> MsgElements; try { // LINE タブをアクティブにする this.chrome.SwitchWindowLine(); // アクティブ前に新着メッセージ数を取得 int msgNumbder = getRoomNewArrivalsMsgNumber(roomName); // 取得する部屋をアクティブに RoomAvtive(roomName); // メッセージルームの一番最後のをメッセージを取得 MsgElements = chrome.FindElementsByXPath(Constants.XPATH_LINE_ChatRoomMsgsOther); // メッセージ受信の起点となる時間 DateTime RceivedTime = DateTime.Now; // 受信から3分以内のメッセージを取得 // 最後から見ていく for (int i = MsgElements.Count - 1; (MsgElements.Count - 1) - msgNumbder < i; i--) { // メッセージリスト IWebElement msgEleBlock = MsgElements.ElementAt(i); // 受信メッセージ string tmpMsg = msgEleBlock.Text; // 改行で区切ってリスト化する string[] tmpAry = tmpMsg.Split(new string[] { "\r\n" }, StringSplitOptions.None); // メッセージの受信時間 (配列の一番末尾が時間) DateTime msgTime = DateTime.Parse(tmpAry[tmpAry.Length - 1]); if (msgTime > RceivedTime.AddMinutes(-3)) { // 受信してから3分以内 又は 指定した数まで取得 // メッセージ要素を取得 //IWebElement msgElement = msgEleBlock.FindElement(By.XPath("//span[@class='mdRGT07MsgTextInner']")); //rceMsgs.Add(msgElement.Text); // デバッグモード 受信したラインメッセージをテキスト出力 //System.IO.File.AppendAllText(Constants.PATH_BO_HISTORY_TEXT + @"\" + DateTime.Now.ToString("yyyyMMdd") + "LineMessage.txt", roomName + Environment.NewLine); //System.IO.File.AppendAllText(Constants.PATH_BO_HISTORY_TEXT + @"\" + DateTime.Now.ToString("yyyyMMdd") + "LineMessage.txt", msgEleBlock.Text + Environment.NewLine); //System.IO.File.AppendAllText(Constants.PATH_BO_HISTORY_TEXT + @"\" + DateTime.Now.ToString("yyyyMMdd") + "LineMessage.txt", " ===== ===== ===== ===== ===== ===== ===== ===== ===== =====" + Environment.NewLine); string rawMsg = string.Empty; // 格納するワーク用文字列 // もし、部屋がLine@だった場合はメッセージ送信者が最初の文字列に入らないので格納する必要がある switch (roomName) { case Constants.ROOM_NAME_SignalMeijin: // Line@だったので飛ばしたメッセージ配列[0]を入れる(Line@の部屋での1行目) rawMsg = rawMsg + tmpAry[0] + Constants.LINE_CRLF; break; default: // Line@以外の部屋は配列[0]は送信者の名前なので飛ばす break; } // 最初と最後以外を連結して格納 // 改行でSplitをした最初の配列にはメッセージ送信者の名前が入っているのでFor文は1から入れる(Line@以外) for (int n = 1; n < tmpAry.Count() - 1; n++) { rawMsg = rawMsg + tmpAry[n] + Constants.LINE_CRLF; } //System.IO.File.AppendAllText(Constants.PATH_BO_HISTORY_TEXT + @"\" + DateTime.Now.ToString("yyyyMMdd") + "LineMessage.txt", rawMsg.Replace(Constants.LINE_CRLF, "/CRLF/") + Environment.NewLine); //System.IO.File.AppendAllText(Constants.PATH_BO_HISTORY_TEXT + @"\" + DateTime.Now.ToString("yyyyMMdd") + "LineMessage.txt", "------------------------------------------------------" + Environment.NewLine); rceMsgs.Add(rawMsg); } else { break; // 3分以上前なら抜ける } } return(rceMsgs); } catch (Exception e) { CommonControl.DebugPrint(e, "getSignalOrder"); return(rceMsgs); //throw e;f } }
/// <summary> /// 親機用ライングループ 待機処理 /// </summary> /// <param name="Line">ラインオブジェクト</param> /// <returns></returns> private static string WaitLineGroupsByParent(LINEControl Line) { // ライン部屋 Line.IsActivate(); // TODO:待機用の部屋をアクティブにして待つ(LINE新着の数字を取得するため) // 今は仮でデバッグ部屋にする Line.RoomAvtive(Constants.ROOM_NAME_DebugRoomName); Line.ChatRoomListScrollTop(); //var tasks = new List<Task>(); string ret = string.Empty; string[] roomNames; //roomNames = new string[] { // Constants.ROOM_NAME_RISE, // Constants.ROOM_NAME_AUXESIS, // Constants.ROOM_NAME_CmdLine, // Constants.ROOM_NAME_MIYU }; roomNames = new string[] { "", Constants.ROOM_NAME_AUXESIS, Constants.ROOM_NAME_CmdLine, Constants.ROOM_NAME_SignalMeijin }; var task1 = Task.Run(() => Line.WaitRoomNewArrivals(roomNames[0])); var task2 = Task.Run(() => Line.WaitRoomNewArrivals(roomNames[1])); var task3 = Task.Run(() => Line.WaitRoomNewArrivals(roomNames[2])); var task4 = Task.Run(() => Line.WaitRoomNewArrivals(roomNames[3])); // 何れかに着信が来るまでまつ int taskNum = Task.WaitAny(task1, task2, task3, task4); // 帰ってきた値の部屋が本当に新着があるか確認する if (Line.ConfirmIsRoomsNewArrivals(roomNames[taskNum])) { ret = roomNames[taskNum]; } else { ret = string.Empty; // 来ていない、又は来ていたが無しと判断されたとき(TODO:原因不明 要調査) for (int i = 0; i < roomNames.Length; i++) { // 1つずつ見て本当になかったか確認する if (Line.ConfirmIsRoomsNewArrivals(roomNames[i])) { // debug CommonControl.DebugPrint("WaitLineGroupsByParent", "自身で見に行って発見した", roomNames[i]); // 実は見つかった時 ret = roomNames[i]; break; } } } // 対象のシグナル1の着信 return(ret); }
/// <summary> /// 経済指標のイベントを取得する /// </summary> /// <returns></returns> public void GetInvestingCalender() { EconomicList = new List <invCalender>(); try { // 経済指標にアクセス while (true) { this.chrome.Url = Constants.URL_INVESTING; this.chrome.WaitCompleteDelay(1000); if (this.chrome.Url.Equals(Constants.URL_INVESTING)) { break; } } //指標一覧リスト の要素取得 IReadOnlyCollection <IWebElement> Events; Events = this.chrome.FindElementsByXPath("//tr[contains(@id, 'eventRowId_')]"); foreach (IWebElement ele in Events) { //重要度のチェック IWebElement impTextEle = this.chrome.FindElementByXPath("//*[@id='" + ele.GetAttribute("id") + "']/td[3]"); if (impTextEle.GetAttribute("title").Equals("高い重要性")) { try { // 重要度が高い場合イベントとして記録 invCalender inv = new invCalender(); string[] eveList = ele.Text.Split(new string[] { " " }, StringSplitOptions.None); inv.importance = 3; inv.evTime = DateTime.Parse(eveList[0]); // 時間 inv.brand = eveList[3]; // イベント銘柄 inv.detail = eveList[4] + eveList[5] + eveList[6]; // 内容 EconomicList.Add(inv); } catch (Exception e) { // エラーが出ても継続する CommonControl.DebugPrint(e, "指標の型変換に失敗"); } } } } catch (Exception e) { CommonControl.DebugPrint(e, "経済指標の情報取得に失敗した"); } // debug //invCalender invs = new invCalender //{ // importance = 3, // evTime = DateTime.Now, // 時間 // brand = "USD", // イベント銘柄 // detail = "テスト指標" // 内容 //}; //EconomicList.Add(invs); }
/// <summary> /// ハイローにエントリーする /// </summary> /// <param name="sig">シグナル情報 コンテナ</param> /// <returns>True エントリー成功 / False エントリー失敗</returns> public Boolean EntryHighLow(ref SignalOrder sig) { try { // シグナルのステータスがエントリーのみ実行 if (sig.mainState != SignalState.soEntry) { return(false); } // ハイローをアクティブに this.IsActivate(); // 要素が押せるようにスクロールをトップに chrome.ExecuteScript("document.scrollingElement.scrollTop = 140"); // 対象の取引する銘柄へ移動 // ===== ===== ===== ===== ===== ===== // 銘柄リストを開く // ===== ===== ===== ===== ===== ===== IWebElement BrandList = this.chrome.FindElementByXPath("//*[@id='highlow-asset-filter']"); CommonDriverControl.ScrollTargetElementView(BrandList); BrandList.Click(); CommonControl.SleepWait(500); // ===== ===== ===== ===== ===== ===== // 銘柄を選ぶ // ===== ===== ===== ===== ===== ===== // 検索にかける IWebElement eleSearchBox = this.chrome.FindElementById("searchBox"); eleSearchBox.SendKeys(sig.tradeBrand); CommonControl.SleepWait(200); // ヒットした一番目を選択(1つしかないはず) IWebElement eleResultList = this.chrome.FindElementByXPath("//*[@id='assetsFilteredList']/div[1]"); eleResultList.Click(); // ===== ===== ===== ===== ===== ===== // 15分固定 // ===== ===== ===== ===== ===== ===== IWebElement timeTab = this.chrome.FindElementByXPath( "//*[@id='assetsCategoryFilterZoneRegion']/div/div[2]"); CommonDriverControl.ScrollTargetElementView(timeTab); timeTab.Click(); CommonControl.SleepWait(500); // ===== ===== ===== ===== ===== ===== // エントリーする判定時刻 フレーム時間のタブを見つける // ===== ===== ===== ===== ===== ===== IReadOnlyCollection <IWebElement> frameTimeDigits = this.chrome.FindElementsByXPath("//*[@class='time-digits']"); // 最大3つある フレームタイムの時間を見に行き、同じ時間を探す bool findFrameFlag = false; for (int i = 0; i < frameTimeDigits.Count(); i++) { //シグナル時間の取得 string chkFrameTime = frameTimeDigits.ElementAt(i).GetAttribute("textContent"); // 次のシグナルの時間か? if (sig.tradeTimeFrame.Equals(chkFrameTime)) { // 表示 frameTimeDigits.ElementAt(i).Click(); findFrameFlag = true; // 見つかった break; // 1つしかない } } // 見つからなかったとき if (findFrameFlag == false) { // エントリー失敗 CommonControl.DebugPrint("entryHighLow", "対象のタイムフレーム時間が見つからなかった為、エントリー出来ませんでした"); CommonControl.DebugPrint("探そうとしたタイムフレーム" + sig.tradeTimeFrame); return(false); } CommonControl.SleepWait(500); // ===== ===== ===== ===== ===== ===== // エントリー金額を入力する // ===== ===== ===== ===== ===== ===== // TODO:実際は総資金の10分の1入札する この仕組みは後に作る 今は単純に10分の1でエントリーする // 10分1が20万を超えた場合は以下のようにする // 例:22万円の場合、11万*2回エントリーする // 30万円の場合、15万円*2回エントリーする // 残高 // タイムフレームを押した後、読み込み中である可能性があるので取得可能になるまで待つ(GetSafeWebElementById) IWebElement eleBalance = CommonDriverControl.GetSafeWebElementById(chrome, Constants.HTML_ID_HL_Balance); int balance = int.Parse(eleBalance.GetAttribute("textContent") .Replace(@"¥", "").Replace(",", "")); // 入力 IWebElement eleAmount = chrome.FindElementById(Constants.HTML_ID_HL_Amount); // TODO:たまに失敗してる? 要調査 念のため2回おこなう CommonDriverControl.ScrollTargetElementView(eleAmount); // 見えていないとクリアできない CommonDriverControl.ScrollTargetElementView(eleAmount); // 見えていないとクリアできない eleAmount.Clear(); // 既存入力額をクリア CommonControl.SleepWait(200); int amount = balance / 2000; // 資産の 20分の1で amount = amount * 100; // 100の倍数にする if (amount < 1000) { amount = 1000; // 1000円未満になった場合は1000円 } if (amount > 200000) { amount = 200000; // 20万を超える場合は20万 (20万以上はエントリーできないため) } eleAmount.SendKeys(amount.ToString()); // ===== ===== ===== ===== ===== ===== // High Or Low 入力 // ===== ===== ===== ===== ===== ===== // 要素が押せるようにスクロールトップの調整 chrome.ExecuteScript("document.scrollingElement.scrollTop = 275"); IWebElement btn; switch (sig.arrow) { case arrowState.asLow: btn = this.chrome.FindElementByXPath(Constants.XPATH_HL_Low_Button); break; case arrowState.asHigh: btn = this.chrome.FindElementByXPath(Constants.XPATH_HL_High_Button); break; default: CommonControl.DebugPrint("ハイ、又はローが分かりませんでした。"); return(false); } btn.Click(); CommonControl.SleepWait(200); // ===== ===== ===== ===== ===== ===== // エントリー時間になるまで待つ // ===== ===== ===== ===== ===== ===== IWebElement rTime = this.chrome.FindElementByXPath(Constants.XPATH_HL_Remaining_Time); string[] timeTxt = rTime.GetAttribute("textContent").Split(new string[] { ":" }, StringSplitOptions.None); // 後どれだけ待てば良いかを求める 5分前まで TimeSpan tsReman = new TimeSpan(0, int.Parse(timeTxt[0]), int.Parse(timeTxt[1])) - new TimeSpan(0, 5, 0); while (true) { // 残り時刻が5分切るまで待機 if (tsReman > new TimeSpan(0, 0, 0)) { CommonControl.SleepWait((int)tsReman.TotalMilliseconds); } break; } // 成功するまで エントリーを行う int tryTime = 0; bool entryFlag = false; while (entryFlag == false) { IWebElement entryBtn = this.chrome.FindElementById("invest_now_button"); entryBtn.Click(); CommonControl.SleepWait(1250); IWebElement eleNotice = this.chrome.FindElementById(Constants.HTML_ID_HL_NoticeMsg); if (eleNotice.Text.Equals("成功")) { //エントリーに成功した entryFlag = true; } tryTime += 1; if (tryTime > 2) { break; // 3回目失敗したら強制終了 } } #if debug if (tryTime == 3) { CommonControl.DebugPrint("3回エントリー失敗した"); } #endif // 処理自体のエントリー結果を返す return(entryFlag); } catch (Exception e) { // エントリーに失敗した CommonControl.DebugPrint(e, "EntryHighLow エントリーに失敗しました"); //throw;// 投げない return(false); } }