private bool TryOpenMoreDeals(double bottomAsk, double topBid, double spreadToOpen) { int zoneIndex = OrderGrid.GetZoneIndex(spreadToOpen); if (zoneIndex == -1) { return(false); } double baseAmount = GetRemainAmountForZoneInBaseCurrency(zoneIndex); if (baseAmount == 0) { return(false); } double buyAmount = CalculateLongBuyAmountByBaseAmount(baseAmount); double actualBuyAmount = GetActualBottomAskAmount(bottomAsk); double finalBuyAmount = Math.Min(buyAmount, actualBuyAmount); double requiredShortSellAmount = CalculateRequiredShortAmount(finalBuyAmount, spreadToOpen); double availableShortSellAmount = GetActualShortBidAmount(topBid); double finalSellAmount = Math.Min(requiredShortSellAmount, availableShortSellAmount); if (finalSellAmount < requiredShortSellAmount) { finalSellAmount = availableShortSellAmount; finalBuyAmount = CalculateRequiredLongAmount(finalSellAmount, spreadToOpen); } MarketBuy(Long, bottomAsk, finalBuyAmount); MarketSell(Short, topBid, finalSellAmount); var order = new StatisticalArbitrageOrderInfo() { LongAmount = finalBuyAmount, LongValue = bottomAsk, ShortAmount = finalSellAmount, ShortTotalAmount = finalSellAmount, ShortValue = topBid, ZoneIndex = zoneIndex, SpentDeposit = Long.HighestBidInBaseCurrency() * finalBuyAmount, Spread = spreadToOpen }; LastItem = new StatisticalArbitrageHistoryItem(); LastItem.Time = DateTime.UtcNow; LastItem.Earned = Earned; LastItem.LongPrice = bottomAsk; LastItem.ShortPrice = topBid; LastItem.LongAmount = finalBuyAmount; LastItem.ShortAmount = finalSellAmount; LastItem.Open = true; StrategyData.Add(LastItem); //OpenedOrders.Add(order); OnOrderOpened(LastItem); return(true); }
private void OnOrderOpened(StatisticalArbitrageHistoryItem lastItem) { string text = string.Empty; text += "<b>" + Name + "</b> open order:"; text += "<pre> buy: " + lastItem.LongPrice.ToString("0.########") + " am = " + lastItem.LongAmount.ToString("0.########") + "</pre>"; text += "<pre> sell: " + lastItem.ShortPrice.ToString("0.########") + " am = " + lastItem.ShortAmount.ToString("0.########") + "</pre>"; TelegramBot.Default.SendNotification(text, ChatId); LogManager.Default.Add(LogType.Success, this, null, "open order", "buy " + lastItem.LongPrice.ToString("0.########") + " am = " + lastItem.LongAmount.ToString("0.########") + " sell" + lastItem.ShortPrice.ToString("0.########") + " am = " + lastItem.ShortAmount.ToString("0.########")); }
private bool TryCloseDeals(double bottomBid, double topAsk, double spreadToClose) { if (spreadToClose > CloseSpread) { return(false); } if (OpenedOrders.Count == 0) { return(false); } StatisticalArbitrageOrderInfo order = GetOpenedOrderWithMaxSpread(); double actualSellAmount = GetActualBottomBidAmount(bottomBid); double finalSellAmount = Math.Min(actualSellAmount, order.LongAmount); double koeffSell = finalSellAmount / order.LongAmount; double actualBuyAmount = GetActualShortAskAmount(topAsk); double finalBuyAmount = Math.Min(actualBuyAmount, order.ShortAmount); double koeffBuy = finalBuyAmount / order.ShortAmount; double koeff = Math.Min(koeffBuy, koeffSell); finalSellAmount *= koeff; finalBuyAmount *= koeff; MarketSell(Long, bottomBid, finalSellAmount); MarketBuy(Short, topAsk, finalBuyAmount); order.LongAmount -= finalSellAmount; order.ShortAmount -= finalBuyAmount; double eInc = (1 / order.LongValue - 1 / order.ShortValue) * finalBuyAmount; Earned += eInc; LastItem = new StatisticalArbitrageHistoryItem(); LastItem.Time = DateTime.UtcNow; LastItem.Earned = Earned; LastItem.LongAmount = finalSellAmount; LastItem.LongPrice = bottomBid; LastItem.ShortPrice = topAsk; LastItem.ShortAmount = finalBuyAmount; LastItem.Close = true; StrategyData.Add(LastItem); //if(order.LongAmount <= 0 && order.ShortAmount <= 0) // OpenedOrders.Remove(order); OnOrderClosed(LastItem); return(true); }
protected override void OnTickCore() { base.OnTickCore(); double bottomAsk = 0; double topBid = 0; double bottomBid = 0; double topAsk = 0; if (Long.OrderBookStatus != TickerDataStatus.Actual || Short.OrderBookStatus != TickerDataStatus.Actual) { string longOb = Long.OrderBookStatus == TickerDataStatus.Actual ? "green" : "red"; string shortOb = Short.OrderBookStatus == TickerDataStatus.Actual ? "green" : "red"; StateTextCore = "<b><color=" + longOb + ">long order book status = " + Long.OrderBookStatus + "</color> <color=" + shortOb + ">short order book status = " + Short.OrderBookStatus + "</b>"; return; } bottomAsk = Long.OrderBook.LowestAsk; topBid = Short.OrderBook.HighestBid; bottomBid = Long.OrderBook.HighestBid; topAsk = Short.OrderBook.LowestAsk; double spreadToOpen = topBid - bottomAsk; double spreadToClose = topAsk - bottomBid; if (LastItem == null || LastItem.LongAsk != bottomAsk || LastItem.ShortBid != topBid) { LastItem = new StatisticalArbitrageHistoryItem(); LastItem.Time = DataProvider.CurrentTime; LastItem.LongAsk = bottomAsk; LastItem.LongBid = bottomBid; LastItem.ShortBid = topBid; LastItem.ShortAsk = topAsk; LastItem.Earned = Earned; LastItem.Index = StrategyData.Count; StrategyData.Add(LastItem); StateTextCore = "<b><color=green>long=" + LastItem.LongAsk.ToString("0.########") + "</color> <color=red> short=" + LastItem.ShortBid.ToString("0.########") + "</color> spread = " + LastItem.OpenSpread.ToString("0.00000000") + " order count = " + OpenedOrders.Count + "</b>"; } if (TryOpenMoreDeals(bottomAsk, topBid, spreadToOpen)) { } else if (TryCloseDeals(bottomBid, topAsk, spreadToClose)) { } }
private bool TryOpenMoreDeals(double bottomAsk, double topBid, double spreadToOpen) { if (spreadToOpen < SpreadOpenPosition) { return(false); } //int zoneIndex = OrderGrid.GetZoneIndex(spreadToOpen); //if(zoneIndex == -1) // return false; //double baseAmount = GetRemainAmountForZoneInBaseCurrency(zoneIndex); //if(baseAmount == 0) // return false; double baseAmount = MaxAllowedDeposit * 0.9; double buyAmount = CalculateLongBuyAmountByBaseAmount(baseAmount); double actualBuyAmount = GetActualBottomAskAmount(bottomAsk); double finalBuyAmount = Math.Min(buyAmount, actualBuyAmount); double requiredShortSellAmount = CalculateRequiredShortAmount(finalBuyAmount, spreadToOpen); double availableShortSellAmount = GetActualShortBidAmount(topBid); double finalSellAmount = Math.Min(requiredShortSellAmount, availableShortSellAmount); if (finalSellAmount < requiredShortSellAmount) { finalSellAmount = availableShortSellAmount; finalBuyAmount = CalculateRequiredLongAmount(finalSellAmount, spreadToOpen); } if (finalBuyAmount == 0 || finalSellAmount == 0 || finalBuyAmount * bottomAsk < MinDepositForOpenPosition) { return(false); } var order = new StatisticalArbitrageOrderInfo() { ShortValue = topBid, SpentDeposit = Long.HighestBidInBaseCurrency() * finalBuyAmount, Spread = spreadToOpen }; if (Long.SpentInBaseCurrency(bottomAsk, finalBuyAmount) * 1.05 > MaxAllowedDeposit) { LogManager.Default.Add(LogType.Error, this, Name, "not enough deposit for open long position", "spent = " + Long.SpentInBaseCurrency(bottomAsk, finalBuyAmount) + " in " + Long.BaseCurrency + "; deposit = " + MaxAllowedDeposit); return(false); } if (Short.SpentInBaseCurrency(topBid, finalSellAmount) * 1.05 > GetMaxAllowedShortDeposit()) { LogManager.Default.Add(LogType.Error, this, Name, "not enough deposit for open long position", "spent = " + Short.SpentInBaseCurrency(topBid, finalSellAmount) + " in " + Short.BaseCurrency + "; deposit = " + GetMaxAllowedShortDeposit()); return(false); } OpenedPairs.Add(order); OpenPositionInfo lp = OpenLongPosition(Long, "OL", bottomAsk, finalBuyAmount, 1000); if (lp == null) { OpenedPairs.Remove(order); LogManager.Default.Add(LogType.Error, this, Name, "failed open long position", "price = " + bottomAsk + "; amount = " + finalBuyAmount + "; spent = " + Long.SpentInBaseCurrency(bottomAsk, finalBuyAmount) + " in " + Long.BaseCurrency); return(false); } OpenPositionInfo sp = OpenShortPosition(Short, "OS", topBid, finalSellAmount, 1000); if (sp == null) { OpenedPairs.Remove(order); LogManager.Default.Add(LogType.Error, this, Name, "failed open short position", "price = " + topBid + "; amount = " + finalSellAmount + "; spent = " + Short.SpentInBaseCurrency(topBid, finalSellAmount)); return(false); } order.LongPosition = lp; order.ShortPosition = sp; order.LongAmount = lp.OpenAmount; order.LongValue = lp.OpenValue; order.ShortAmount = sp.OpenAmount; order.ShortTotalAmount = sp.OpenValue; LastItem = new StatisticalArbitrageHistoryItem(); LastItem.OpenedPositions.Add(order.LongPosition); LastItem.OpenedPositions.Add(order.ShortPosition); LastItem.Time = DataProvider.CurrentTime; LastItem.Earned = Earned; LastItem.LongBid = Long.OrderBook.HighestBid; LastItem.LongAsk = bottomAsk; LastItem.ShortBid = topBid; LastItem.ShortAsk = Short.OrderBook.LowestAsk; LastItem.LongAmount = finalBuyAmount; LastItem.ShortAmount = finalSellAmount; LastItem.Open = true; LastItem.Index = StrategyData.Count; LastItem.Mark = "OPEN"; StrategyData.Add(LastItem); //OpenedOrders.Add(order); OnOrderOpened(LastItem); return(true); }
private bool TryCloseDeals(double bottomBid, double topAsk, double spreadToClose) { if (spreadToClose > SpreadClosePosition) { return(false); } if (OpenedOrders.Count == 0) { return(false); } //StatisticalArbitrageOrderInfo order = GetOpenedOrderWithMaxSpread(); foreach (StatisticalArbitrageOrderInfo order in OpenedPairs) { if (order.Spread < SpreadClosePosition) { continue; } double actualLongCloseBid = Long.GetActualBidByAmount(order.LongAmount); double actualShortCloseAsk = Short.GetActualAskByAmount(order.ShortAmount); double spread = actualShortCloseAsk - actualLongCloseBid; if (spread > SpreadClosePosition) { continue; } double actualSellAmount = GetActualBottomBidAmount(actualLongCloseBid); double actualBuyAmount = GetActualShortAskAmount(actualShortCloseAsk); double finalSellAmount = Math.Min(actualSellAmount, order.LongAmount); double koeffSell = finalSellAmount / order.LongAmount; double finalBuyAmount = Math.Min(actualBuyAmount, order.ShortAmount); double koeffBuy = finalBuyAmount / order.ShortAmount; double koeff = Math.Min(koeffBuy, koeffSell); finalSellAmount *= koeff; finalBuyAmount *= koeff; TradingResult closeLong = MarketSell(Long, bottomBid, finalSellAmount); TradingResult closeShort = MarketBuy(Short, topAsk, finalBuyAmount); order.LongAmount -= closeLong.Amount; order.ShortAmount -= closeShort.Amount; //double eInc = (1 / order.LongValue - 1 / order.ShortValue) * finalBuyAmount; //Earned += eInc; LastItem = new StatisticalArbitrageHistoryItem(); LastItem.Time = DataProvider.CurrentTime; LastItem.Earned = Earned; LastItem.LongAmount = finalSellAmount; LastItem.LongAsk = Long.OrderBook.LowestAsk; LastItem.LongBid = bottomBid; LastItem.ShortAsk = topAsk; LastItem.ShortBid = Short.OrderBook.HighestBid; LastItem.ShortAmount = finalBuyAmount; LastItem.Close = true; LastItem.Index = StrategyData.Count; LastItem.Mark = "CLOSE"; LastItem.ClosedPositions.Add(order.LongPosition); LastItem.ClosedPositions.Add(order.ShortPosition); StrategyData.Add(LastItem); CloseLongPosition(order.LongPosition, closeLong); CloseShortPosition(order.ShortPosition, closeShort); if (order.LongAmount <= 0 && order.ShortAmount <= 0) { OpenedPairs.Remove(order); OnOrderClosed(LastItem); } else { throw new Exception("Partial Close Not Implemented"); } } return(true); }