/** * 価格乖離 + SFD表示 */ private async void UpdateInfoAsync(object sender, EventArgs e) { var statusInfo = await BitFlyerApiModel.GetServerStatus(); if (statusInfo != null) { ServerStatusValueLabel.Text = statusInfo.health; } var sepalationPriceRate = await BitFlyerApiModel.GetPriceSepalationRate(); if (sepalationPriceRate > 0) { PriceSepalationValueLabel.Text = sepalationPriceRate + "%"; SFDRateLabel.Text = (sepalationPriceRate >= 20 ? " (SFD:2.00%)" : sepalationPriceRate >= 15 ? " (SFD:1.00%)" : sepalationPriceRate >= 10 ? " (SFD:0.50%)" : sepalationPriceRate >= 5 ? " (SFD:0.25%)" : ""); } // Bitflyerは現在価格の50%未満200%以上の金額はエラーになる // 入力制限してしまった方が楽なので制限する var ltp = BitFlyerApiModel.getLastFxLtp(); if (ltp > 0) { PriceInputBox.Minimum = ltp * 0.5m; PriceInputBox.Maximum = ltp * 2; } }
/** * 最新価格を入札価格に設定 **/ private async void LoadPriceButton_Click(object sender, EventArgs e) { var price = await BitFlyerApiModel.GetFxLastPrice(); if (price > 0) { PriceInputBox.Value = price; } }
private async void CancelAllButton_Click(object sender, EventArgs e) { OrderCheckTimer.Stop(); SetCancelResult("Waiting"); var result = await BitFlyerApiModel.CancelAllChildOrder(); SetCancelResult(result ? "SUCCESS" : "FAILED"); if (result) { OrderGridView_Timer(null, null); } OrderCheckTimer.Start(); }
private async void CollateralCheckTimer_Tick(object sender, EventArgs e) { var timer = (Timer)sender; timer.Stop(); var collateral = await BitFlyerApiModel.GetCollateral(); if (collateral != null) { CollateralValue.Text = collateral.collateral.ToString("N0") + "円"; KeepRateValue.Text = collateral.keep_rate.ToString("P1"); } timer.Start(); }
private async void OrderGridView_CellClick(object sender, DataGridViewCellEventArgs e) { DataGridView grid = (DataGridView)sender; if (grid.Columns[e.ColumnIndex].Name == "Cancel") { OrderCheckTimer.Stop(); SetCancelResult("Waiting"); var id = grid["ChildOrderAcceptanceId", e.RowIndex].Value.ToString(); var result = await BitFlyerApiModel.CancelChildOrder(id); SetCancelResult(result ? "SUCCESS" : "FAILED"); // 成功時、リスト更新を呼んでおく if (result) { OrderGridView_Timer(null, null); } OrderCheckTimer.Start(); } }
private async void OrderGridView_Timer(object sender, EventArgs e) { lock (orderListLock) { if (orderTimerLockFlg) { return; } orderTimerLockFlg = true; } OrderCheckTimer.Stop(); /** * DataGridに表示したいもの * 注文命令を出して、child_ochild_order_acceptance_idが発行されたが、注文一覧に未反映の物 * 注文一覧に反映済みのもの * 注文処理が終わったものは消去 **/ var list = await BitFlyerApiModel.GetOrderList(); if (list != null) { // 最新のchild_order_listを保存 var orderRecodeSet = new HashSet <string>(); list.ForEach(info => { // 注文情報を生成 var orderInfo = new OrderInfo() { //OrderDateTime //ServerResponsedTime //ElapsedTime OrderType = info.child_order_type, OrderAcceptTime = Util.FormatDateIsoToLocal(info.child_order_date, Util.DATETIME_FORMAT_MDHMS), ExpireDate = Util.FormatDateIsoToLocal(info.expire_date, Util.DATETIME_FORMAT_MDHMS), Side = info.side, OrderPrice = info.price, OrderSize = info.size, RemainingSize = info.outstanding_size, AveragePrice = info.average_price, Cancel = "×", ChildOrderAcceptanceId = info.child_order_acceptance_id, ChildOrderId = info.child_order_id }; orderRecodeSet.Add(info.child_order_acceptance_id); lock (bsMap) { if (bsMap.ContainsKey(info.child_order_acceptance_id)) { // 既にGridに追加されていれば上書きする // 未承認データの場合は、その項目を追加してから上書きする var index = orderBs.List.IndexOf(bsMap[info.child_order_acceptance_id]); if (!orderInfo.Equals(orderBs.List[index])) { // このデータだけは注文時の物を利用するので引き継ぐ orderInfo.OrderDateTime = ((OrderInfo)orderBs.List[index]).OrderDateTime; orderBs.List[index] = orderInfo; bsMap[info.child_order_acceptance_id] = orderInfo; } } else { // bsMapとGridに追加する orderBs.Add(orderInfo); bsMap.Add(info.child_order_acceptance_id, orderInfo); } } }); lock (bsMap) { // 保有済みのデータをチェックし古いデータを取り除く foreach (var childId in bsMap.Keys.Reverse()) { // 最新情報にあるのでスルー if (orderRecodeSet.Contains(childId)) { continue; } var orderInfo = bsMap[childId]; // 今回の確認リストにないが、既に承認済みのレコードは消去 // 注文確定待ち(childOrderIdが未発行の物は残したい) if (orderInfo.ChildOrderId != null || orderInfo.CheckCounter++ > 30) { orderBs.List.Remove(bsMap[childId]); bsMap.Remove(childId); } } // タイミングが悪いと、orderBsだけ残る場合がある // Lockを増やすより、上書きした方がコストがかからない if (bsMap.Count() == 0) { orderBs.Clear(); } } } OrderCheckTimer.Start(); lock (orderListLock) orderTimerLockFlg = false; }
private async void PositionGridView_Timer(object sender, EventArgs e) { lock (positionListLock) { if (positionTimerLockFlg) { return; } positionTimerLockFlg = true; } var list = await BitFlyerApiModel.GetPositionList(); var ltp = BitFlyerApiModel.getLastFxLtp(); if (list != null) { lock (positionBs) { positionBs.Clear(); decimal wAvePrice = 0, sizeSum = 0, pnlSum = 0, collateralSum = 0; string side = ""; list.ForEach(row => { side = row.side; // ltpが取得できていたら値幅を計算 if (ltp > 0) { row.PriceBand = (side == BitFlyerApiModel.SIDE_BUY ? ltp - row.price : row.price - ltp); } wAvePrice += row.price * row.size; sizeSum += row.size; pnlSum += row.pnl; collateralSum += row.require_collateral; // 既にGridに追加されていれば上書きする var index = positionBs.List.IndexOf(row); if (index >= 0) { positionBs.List[index] = row; } else { positionBs.Add(row); } }); if (list.Count == 0) { positionBs.Clear(); positionSumBs.Clear(); } else { wAvePrice = (wAvePrice / sizeSum); var info = new PositionSummaryInfo( wAvePrice, sizeSum, pnlSum, collateralSum, (ltp > 0 && wAvePrice > 0 ? (side == BitFlyerApiModel.SIDE_BUY ? ltp - wAvePrice : wAvePrice - ltp) : 0) ); if (positionSumBs.Count == 0) { positionSumBs.Add(info); } else { positionSumBs.List[0] = info; } } } } lock (positionListLock) positionTimerLockFlg = false; }
/** * 入札処理を実行 **/ private async void OrderButton_Click(object sender, EventArgs e) { var button = (System.Windows.Forms.Button)sender; var inputPrice = PriceInputBox.Value; var ltp = BitFlyerApiModel.getLastFxLtp(); var side = (button.Name == "BuyButton") ? BitFlyerApiModel.SIDE_BUY : BitFlyerApiModel.SIDE_SELL; if (FixInputPrice == "ExceptPopularPrice") { // 50で割り切れる数字はNG if (inputPrice % 50 == 0) { inputPrice = inputPrice + (side == BitFlyerApiModel.SIDE_BUY ? 3 : -3); } // 1は避ける 99も避ける if (inputPrice % 10 == 1 || inputPrice % 100 == 99) { inputPrice = inputPrice + (side == BitFlyerApiModel.SIDE_BUY ? 3 : -3); } } if (ltp < 0) { SetOrderResult("GetLtpError"); return; } else { // 不利な方向のミス注文を防ぎたい // 価格よりN%以上高い買い注文を拒否 // 価格よりN%以上低い売り注文を拒否 if (side == BitFlyerApiModel.SIDE_BUY) { if (ltp * (OrderSaftyLimit / 100m + 1) < inputPrice) { SetOrderResult("SaftyLimit"); return; } } else { if (ltp * (1 - (OrderSaftyLimit / 100m)) > inputPrice) { SetOrderResult("SaftyLimit"); return; } } } if (button.Enabled) { var listForm = OrderListForm.Instance; SetOrderResult("Waiting"); button.Enabled = false; var result = await BitFlyerApiModel.Order(side, inputPrice, SizeInputBox.Value, GetOrderExpireValue()); var acceptId = result; bool isSuccess = acceptId != null && acceptId.Length > 0 ? true : false; if (isSuccess) { OrderListForm.Instance.AddOrderInfo( BitFlyerApiModel.CHILD_ORDER_TYPE_LIMIT , DateTime.UtcNow.ToString() , side , inputPrice , SizeInputBox.Value , acceptId); } SetOrderResult(isSuccess ? "SUCCESS" : "ERROR"); button.Enabled = true; } }