public async override void RefreshView() { DateValues.Clear(); PortfolioValues.Clear(); // Determine frequency to use var valueFrequency = ValueFrequency.Daily; var timeSpan = _Parameter.DateRange.ToDate - _Parameter.DateRange.FromDate; if (timeSpan.Days > 365 * 5) { valueFrequency = ValueFrequency.Monthly; } else if (timeSpan.Days > 365) { valueFrequency = ValueFrequency.Weekly; } PortfolioValueResponse response; if (_Parameter.Stock.Id == Guid.Empty) { response = await _Parameter.RestClient.Portfolio.GetValue(_Parameter.DateRange, valueFrequency); } else { response = await _Parameter.RestClient.Holdings.GetValue(_Parameter.Stock.Id, _Parameter.DateRange, valueFrequency); } if (response == null) { return; } // create chart data var values = new List <double>(); foreach (var value in response.Values) { DateValues.Add(value.Date.ToShortDateString()); values.Add((double)value.Amount); } PortfolioValues.AddRange(values); }
private async Task _binanceWsClient_UserStreamUpdateReceived(object sender, BinanceUserStreamUpdateEventArgs args) { var update = args.Update; if (update.EventType == "ACCOUNT_UPDATE" && update.BalancePosition?.Balances != null) { Debug.WriteLine($"[{DateTime.UtcNow.ToString("dd - MM - yyyy hh: mm:ss")}] User stream update received: {JsonConvert.SerializeObject(update)}"); var usdtBalance = update.BalancePosition.Balances.FirstOrDefault(b => b.Asset == "USDT"); if (usdtBalance != null) { PortfolioValues.Add(usdtBalance.WalletBalance ?? 0.0m); decimal currMarketMeanPrice = 0; var lastPrices = _binanceWsClient.WholeMarketKlines.Select(k => k.Value.LastOrDefault()?.Kline?.ClosePrice ?? 0).ToList(); currMarketMeanPrice = (decimal)lastPrices.Average(); MarketMeanPrices.Add(currMarketMeanPrice); if (MarketMeanPrices.Count >= 2) { CumulatedMarketPerf += MarketPerfs.Last(); CumulatedPotfolioPerf += PortfolioPerfs.Last(); } if (MarketMeanPrices.Count > MAX_PERFS_HIST) { MarketMeanPrices.RemoveAt(0); PortfolioValues.RemoveAt(0); } decimal returnWithfees = CumulatedPotfolioPerf * (InitPortfolioValue / _parameters.FixedInvestedQuoteAssetQty); decimal fees = (-1) * NbTradeCycles * DOUBLE_FEES_RATE; Debug.WriteLine($"[{DateTime.UtcNow.ToString("dd-MM-yyyy HH:mm:ss")}] Cumul. portfolio return (ren. by invest. size) = {returnWithfees} (cumul. gross: {returnWithfees - fees} -- cumul. fees = {fees}) -- cumul. market return = {CumulatedMarketPerf} "); } //if (_parameters.DoPlaceMarketOrders) //{ // IEnumerable<string> liquidatedSymbols = CurrentHoldBaseAssetPos.Where(p => p.Value.Side != 0).Select(p => p.Key) // .Except(update.BalancePosition?.Positions.Select(p => p.Symbol.ToLower())); // foreach(var symbol in liquidatedSymbols) // { // await _binanceWsClient.CancelAllOpenOrders(symbol); // await Task.Delay(DELAY_BETWEEN_ORDERS_IN_MILLISECS); // } //} } if (update.EventType == "ORDER_TRADE_UPDATE") { Debug.WriteLine($"[{DateTime.UtcNow.ToString("dd - MM - yyyy hh: mm:ss")}] Ordre trade update: {JsonConvert.SerializeObject(update)}"); if (update.OrderUpdate != null && _parameters.DoPlaceMarketOrders && update.OrderUpdate.OrderType == "MARKET" && (update.OrderUpdate.Side == "BUY" || update.OrderUpdate.Side == "SELL") && CurrentHoldBaseAssetPos[update.OrderUpdate.Symbol.ToLower()].Side == (update.OrderUpdate.Side == "BUY" ? 1 : update.OrderUpdate.Side == "SELL" ? -1 : 0) && (update.OrderUpdate.OrderStatus == "FILLED" || update.OrderUpdate.OrderStatus == "PARTIALLY_FILLED")) { string symbol = update.OrderUpdate.Symbol.ToLower(); decimal entryPrice = (decimal)update.OrderUpdate.LastFilledPrice; string side = update.OrderUpdate.Side; decimal qty = (decimal)update.OrderUpdate.OrderLastFilledQuantity; var stopLoss = new BinanceFuturesPlacedOrder { Symbol = symbol, Side = side == "BUY" ? "SELL" : "BUY", Quantity = qty, Type = "STOP_MARKET", StopPrice = side == "BUY" ? Math.Round(entryPrice * (1 - _parameters.RiskThreshold), ExchangeInfo.Symbols.First(s => s.Symbol.ToLower() == symbol).PricePrecision, MidpointRounding.ToZero) : Math.Round(entryPrice * (1 + _parameters.RiskThreshold), ExchangeInfo.Symbols.First(s => s.Symbol.ToLower() == symbol).PricePrecision, MidpointRounding.AwayFromZero) }; Debug.WriteLine($"[{DateTime.UtcNow.ToString("dd-MM-yyyy HH:mm:ss")}] Avant envoi StopLoss : {JsonConvert.SerializeObject(stopLoss, new JsonSerializerSettings { Formatting = Formatting.None })}"); var trailingTakeProfit = new BinanceFuturesPlacedOrder { Symbol = symbol, Side = side == "BUY" ? "SELL" : "BUY", Quantity = qty, Type = "TRAILING_STOP_MARKET", CallbackRate = Math.Min(0.1m, _parameters.RewardThrIncreaseRate * 100), ActivationPrice = Math.Round(side == "BUY" ? entryPrice * (1 + _parameters.RewardThreshold) : entryPrice * (1 - _parameters.RewardThreshold), ExchangeInfo.Symbols.First(s => s.Symbol.ToLower() == symbol).PricePrecision, MidpointRounding.AwayFromZero) }; Debug.WriteLine($"[{DateTime.UtcNow.ToString("dd-MM-yyyy HH:mm:ss")}] Avant envoi TakeProfit: {JsonConvert.SerializeObject(trailingTakeProfit, new JsonSerializerSettings { Formatting = Formatting.None })}"); var responseStopLoss = await _binanceWsClient.PlaceOrder(stopLoss); CurrentHoldBaseAssetPos[symbol].CurrentStopLosses.Add(responseStopLoss); if (responseStopLoss.IsSuccess && responseStopLoss.Code == null) { Debug.WriteLine($"[{DateTime.UtcNow.ToString("dd-MM-yyyy HH:mm:ss")}] Vente/achat envoyé: {JsonConvert.SerializeObject(responseStopLoss, new JsonSerializerSettings { Formatting = Formatting.None })}"); } else { Debug.WriteLine($"[{DateTime.UtcNow.ToString("dd-MM-yyyy HH:mm:ss")}]Vente/achat non-envoyé: {JsonConvert.SerializeObject(responseStopLoss, new JsonSerializerSettings { Formatting = Formatting.None })}"); } var responseTakeProfit = await _binanceWsClient.PlaceOrder(trailingTakeProfit); CurrentHoldBaseAssetPos[symbol].CurrentTakeProfits.Add(responseTakeProfit); if (responseTakeProfit.IsSuccess && responseTakeProfit.Code == null) { Debug.WriteLine($"[{DateTime.UtcNow.ToString("dd-MM-yyyy HH:mm:ss")}] Vente/achat envoyé: {JsonConvert.SerializeObject(responseTakeProfit, new JsonSerializerSettings { Formatting = Formatting.None })}"); } else { Debug.WriteLine($"[{DateTime.UtcNow.ToString("dd-MM-yyyy HH:mm:ss")}]Vente/achat non-envoyé: {JsonConvert.SerializeObject(responseTakeProfit, new JsonSerializerSettings { Formatting = Formatting.None })}"); } } if (update.OrderUpdate != null && _parameters.DoPlaceMarketOrders && update.OrderUpdate.OrderType == "MARKET" && (update.OrderUpdate.Side == "BUY" || update.OrderUpdate.Side == "SELL") && CurrentHoldBaseAssetPos[update.OrderUpdate.Symbol.ToLower()].Side == (update.OrderUpdate.Side == "BUY" ? -1 : update.OrderUpdate.Side == "SELL" ? 1 : 0) && (update.OrderUpdate.OrderStatus == "FILLED" || update.OrderUpdate.OrderStatus == "PARTIALLY_FILLED")) { string symbol = update.OrderUpdate.Symbol.ToLower(); //Cas de l'execution d'un stop loss/trailing take profit bool isStopLoss = CurrentHoldBaseAssetPos[symbol].CurrentStopLosses.Select(x => x.OrderId).Contains(update.OrderUpdate.OrderId); bool isTakeProfit = CurrentHoldBaseAssetPos[symbol].CurrentTakeProfits.Select(x => x.OrderId).Contains(update.OrderUpdate.OrderId); if (isStopLoss || isTakeProfit) { CurrentHoldBaseAssetPos[symbol].Qty -= update.OrderUpdate.OrderLastFilledQuantity ?? 0; if (CurrentHoldBaseAssetPos[symbol].Qty == 0) { CurrentHoldBaseAssetPos[symbol].Side = 0; CurrentHoldBaseAssetPos[symbol].IsBeingLiquidated = false; CurrentHoldBaseAssetPos[symbol].AvgEntryPrice = 0; CurrentHoldBaseAssetPos[symbol].CurrentStopLosses.Clear(); CurrentHoldBaseAssetPos[symbol].CurrentTakeProfits.Clear(); await _binanceWsClient.CancelAllOpenOrders(symbol); MinutesSinceLastPosition = 0; } else if (update.OrderUpdate.OrderStatus == "FILLED") { long expiredOrderId = update.OrderUpdate.OrderId; if (isTakeProfit) { var removedTakeProfit = CurrentHoldBaseAssetPos[symbol].CurrentTakeProfits.FirstOrDefault(tp => tp.OrderId == expiredOrderId); if (removedTakeProfit != null) { int removedTPIndex = CurrentHoldBaseAssetPos[symbol].CurrentTakeProfits.IndexOf(removedTakeProfit); long mirrorOrderId = CurrentHoldBaseAssetPos[symbol].CurrentStopLosses[removedTPIndex].OrderId; await _binanceWsClient.CancelOrder(symbol, mirrorOrderId); CurrentHoldBaseAssetPos[symbol].CurrentTakeProfits.RemoveAt(removedTPIndex); CurrentHoldBaseAssetPos[symbol].CurrentStopLosses.RemoveAt(removedTPIndex); } } else //if (isStopLoss) { var removedStopLoss = CurrentHoldBaseAssetPos[symbol].CurrentStopLosses.FirstOrDefault(tp => tp.OrderId == expiredOrderId); if (removedStopLoss != null) { int removedStopLossIndex = CurrentHoldBaseAssetPos[symbol].CurrentStopLosses.IndexOf(removedStopLoss); long mirrorOrderId = CurrentHoldBaseAssetPos[symbol].CurrentTakeProfits[removedStopLossIndex].OrderId; await _binanceWsClient.CancelOrder(symbol, mirrorOrderId); CurrentHoldBaseAssetPos[symbol].CurrentTakeProfits.RemoveAt(removedStopLossIndex); CurrentHoldBaseAssetPos[symbol].CurrentStopLosses.RemoveAt(removedStopLossIndex); } } } if (isTakeProfit) { Debug.WriteLine($"[{DateTime.UtcNow.ToString("dd - MM - yyyy hh: mm:ss")}] Diminution/liquidation position sur {symbol} (execution du trailing take profit)"); } else { Debug.WriteLine($"[{DateTime.UtcNow.ToString("dd - MM - yyyy hh: mm:ss")}] Diminution/liquidation position sur {symbol} (execution du stop loss)"); } return; } } } await Task.Run(() => { }); }