public static int GetNewOrderVolume(TradeSignalActionTrade action, TradeSharpConnection ctx, SUBSCRIPTION_SIGNAL tradeSets) { // получить ордера по счету, посчитать актуальный баланс (средства) счета try { var account = ctx.ACCOUNT.FirstOrDefault(a => a.ID == tradeSets.TargetAccount.Value); if (account == null) { Logger.ErrorFormat("Ошибка при расчете объема по счету {0}, ордер {1}: счет не найден", tradeSets.TargetAccount, action.OrderId); return(0); } var equity = (double)account.Balance; // ордера var orders = ctx.POSITION.Where(p => p.AccountID == tradeSets.TargetAccount && p.State == (int)PositionState.Opened).ToList().Select(o => LinqToEntity.DecorateOrder(o)).ToList(); // проверить - нет ли противоположного ордера? var quotes = Contract.Util.BL.QuoteStorage.Instance.ReceiveAllData(); if (orders.Count > 0) { if (!(tradeSets.HedgingOrdersEnabled ?? false)) { var hasOrdersCounter = orders.Any(p => p.Symbol == action.Ticker && p.Side != action.Side); if (hasOrdersCounter) { logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Info, LogMsgContraOrders, 1000 * 60 * 90, "Ордер {0} {1}, счет {2} - есть встречные ордера", action.Side > 0 ? "BUY" : "SELL", action.Ticker, tradeSets.TargetAccount); return(0); } } // посчитать профит по позам bool noQuoteError; var openResult = DalSpot.Instance.CalculateOpenedPositionsCurrentResult( orders, quotes, account.Currency, out noQuoteError); if (noQuoteError) { logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error, LogMsgVolmCalcNoQuote, 1000 * 60 * 90, "GetNewOrderVolume - нет котировки"); return(0); } equity += openResult; } if (equity <= 0) { logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error, LogMsgEquityIsNil, 1000 * 60 * 90, "Баланс счета {0}: {1}", account.ID, equity); return(0); } // посчитать объем var volumeDepo = (tradeSets.PercentLeverage ?? 100) / 100f * equity * (double)action.Leverage; // пересчитать объем в базовую валюту string errorStr; var volumeBase = DalSpot.Instance.ConvertToTargetCurrency(action.Ticker, true, account.Currency, volumeDepo, quotes, out errorStr); if (!volumeBase.HasValue) { logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error, LogMsgVolmToBase, 1000 * 60 * 90, "GetNewOrderVolume - невозможно посчитать объем по сделке {0}, валюта счета {1}: {2}", action.Ticker, account.Currency, errorStr); return(0); } // округлить объем var volume = MarketOrder.RoundDealVolume((int)volumeBase, (VolumeRoundType)(tradeSets.VolumeRound ?? (int)VolumeRoundType.Ближайшее), tradeSets.MinVolume ?? 10000, tradeSets.StepVolume ?? 10000); if (volume == 0) { var msg = string.Format("Полученный объем входа ({0}) округлен до 0", (int)volumeBase); logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error, LogMsgVolmRoundToZero, 1000 * 60 * 90, msg); return(0); } // проверить на превышение плеча if ((tradeSets.MaxLeverage ?? 0) > 0) { var totalExposure = 0M; var ordersBySignaller = orders.Where(position => { int orderSignalCatId, parentDealId; if (MarketOrder.GetTradeSignalFromDeal(position, out orderSignalCatId, out parentDealId)) { return(orderSignalCatId == action.ServiceId); } return(false); }).GroupBy(o => o.Symbol).ToDictionary(o => o.Key, o => o.ToList()); foreach (var orderByTicker in ordersBySignaller) { // суммарная экспозиция var exp = orderByTicker.Value.Sum(o => o.Side * o.Volume); if (orderByTicker.Key == action.Ticker) { exp += action.Side * volume; } if (exp == 0) { continue; } // перевести экспозицию в валюту депозита var expBase = DalSpot.Instance.ConvertToTargetCurrency(action.Ticker, true, account.Currency, volumeDepo, quotes, out errorStr); if (!expBase.HasValue) { logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error, LogMsgExposureNoQuote, 1000 * 60 * 90, "GetNewOrderVolume - невозможно посчитать экспозицию по сделке " + "{0}, тикер {1}: {2}", action.Ticker, orderByTicker.Key, errorStr); return(0); } totalExposure += Math.Abs(expBase.Value); } var totalLeverage = (double)totalExposure / equity; // ReSharper disable PossibleInvalidOperationException if (totalLeverage > tradeSets.MaxLeverage.Value) // ReSharper restore PossibleInvalidOperationException { logNoFlood.LogMessageFormatCheckFlood(LogEntryType.Error, LogMsgMaxLevExceeded, 1000 * 60 * 90, "GetNewOrderVolume - макс плечо ({0}) превышено, " + "тикер {1}: плечо составит {2}", tradeSets.MaxLeverage.Value, action.Ticker, totalLeverage); return(0); } } return(volume); } catch (Exception ex) { Logger.ErrorFormat("Ошибка при расчете объема по счету {0}, ордер {1}: {2}", tradeSets.TargetAccount, action.OrderId, ex); } return(0); }
private static void GetClosedDealsResult( float balance, string depoCurx, Dictionary <string, QuoteData> quotes, Dictionary <int, TradeSignalProfit> signalResult) { List <MarketOrder> orders; try { var status = TradeSharpAccount.Instance.proxy.GetHistoryOrders(AccountStatus.Instance.accountID, null, out orders); if (status != RequestStatus.OK) { Logger.ErrorFormat("SignalProfitReport - не удалось получить закрытые сделки ({0})", status); return; } } catch (Exception ex) { Logger.Error("SignalProfitReport - не удалось получить закрытые сделки:", ex); return; } foreach (var order in orders) { int signalCatId, parentDealId; if (!MarketOrder.GetTradeSignalFromDeal(order, out signalCatId, out parentDealId)) { continue; } TradeSignalProfit result; signalResult.TryGetValue(signalCatId, out result); if (result == null) { result = new TradeSignalProfit(); signalResult.Add(signalCatId, result); } result.closedDeals.Add(order); } // суммарные позы foreach (var result in signalResult.Values) { // список суммарных поз по каждому тикеру - EURUSD, ... if (result.closedDeals.Count == 0) { continue; } var sumPos = PositionSummary.GetPositionSummary(quotes, result.closedDeals, depoCurx, balance); result.closedDeals.Clear(); foreach (var pos in sumPos) { pos.Command = MakeDealsCountString(pos.orders.Count); if (string.IsNullOrEmpty(pos.Symbol)) { continue; } result.closedDeals.Add(new MarketOrder { Side = pos.Side, Symbol = pos.Symbol, Volume = pos.Volume, Comment = pos.Command, ResultPoints = pos.ProfitInPoints, ResultDepo = pos.Profit, ResultBase = pos.ProfitInPercent }); } // суммарная поза var totalPos = sumPos.First(p => string.IsNullOrEmpty(p.Symbol)); sumPos.Remove(totalPos); result.totalClosedDealsCount = sumPos.Sum(p => p.orders.Count); result.totalClosedResult = sumPos.Sum(p => p.Profit); result.totalClosedVolume = totalPos.Volume; } }
private void RenderAccountPositions(StringBuilder sb, int accountId) { List <MarketOrder> orders; var accountInfo = GetAccountInfoFromServer(accountId, out orders); if (accountInfo == null) { return; } var tradeSignalRequestScript = RenderAjaxSignalDetailQuery(sb); // краткая сводка по счету sb.AppendLine(" <h3>Счет " + accountId + "</h3>"); sb.AppendLine(" <p>"); var ptrVal = new Dictionary <string, string> { { "Баланс", accountInfo.Equity.ToStringUniformMoneyFormat() + " " + accountInfo.Currency }, { "Текущая прибыль/убыток", (accountInfo.Equity - accountInfo.Balance).ToStringUniformMoneyFormat() + " " + accountInfo.Currency }, { "Группа", accountInfo.Group } }; foreach (var pair in ptrVal) { sb.AppendLine(" " + pair.Key + ": " + pair.Value + "<br/>"); } sb.AppendLine(" </p>"); // рендерить таблицу открытых позиций RenderTableOpenTag(sb); RenderTableRowTag(sb, true); sb.AppendLine(" <td>№</td><td>Тип</td><td>Объем</td><td>Инстр.</td>" + "<td>Цена</td><td>Время</td><td>Выход</td><td>Результат</td><td>SL</td><td>TP</td><td>Сиг.</td></tr>"); var evenRow = false; var colorSchemeText = new Dictionary <Cortege2 <bool, bool>, string> { { new Cortege2 <bool, bool>(true, true), "Black" }, // even - profit { new Cortege2 <bool, bool>(false, true), "Black" }, // odd - profit { new Cortege2 <bool, bool>(false, false), "Black" }, // odd - loss { new Cortege2 <bool, bool>(true, false), "#860000" } // even - loss }; var colorSchemeBack = new Dictionary <Cortege2 <bool, bool>, string> { { new Cortege2 <bool, bool>(true, true), "White" }, // even - profit { new Cortege2 <bool, bool>(false, true), "#E0E0E0" }, // odd - profit { new Cortege2 <bool, bool>(false, false), "FFD6D6" }, // odd - loss { new Cortege2 <bool, bool>(true, false), "#White" } // even - loss }; foreach (var order in orders) { evenRow = !evenRow; var colorText = colorSchemeText[new Cortege2 <bool, bool>(evenRow, order.ResultDepo >= 0)]; var colorBack = colorSchemeBack[new Cortege2 <bool, bool>(evenRow, order.ResultDepo >= 0)]; sb.AppendLine(string.Format(" <tr style=\"color:{0}; background-color:{1}\">", colorText, colorBack)); int signalCat, parentDeal; var signalString = ""; if (MarketOrder.GetTradeSignalFromDeal(order, out signalCat, out parentDeal)) { signalString = string.Format("<a href=\"#\" onclick=\"{0}({1})\">[{1}]</a>", tradeSignalRequestScript, signalCat); } sb.AppendLine(string.Format(" <td>{0}</td><td>{1}</td><td>{2}</td>" + "<td>{3}</td><td>{4}</td><td>{5:dd.MM.yyyy HH:mm:ss}</td><td>{6}</td><td>{7}</td><td>{8}</td><td>{9}</td><td>{10}</td></tr>", order.ID, order.Side > 0 ? "BUY" : "SELL", order.Volume.ToStringUniformMoneyFormat(), order.Symbol, order.PriceEnter.ToStringUniformMoneyFormat(), order.TimeEnter, (order.PriceExit ?? 0).ToStringUniformPriceFormat(), order.ResultDepo.ToStringUniformMoneyFormat(), order.StopLoss.HasValue ? order.StopLoss.Value.ToStringUniformPriceFormat() : " ", order.TakeProfit.HasValue ? order.TakeProfit.Value.ToStringUniformPriceFormat() : " ", signalString)); } }
private static Dictionary <int, TradeSignalProfit> GetOpenDealsResult( float balance, string depoCurx, Dictionary <string, QuoteData> quotes) { var signalResult = new Dictionary <int, TradeSignalProfit>(); // получить открытые сделки var orders = MarketOrdersStorage.Instance.MarketOrders; foreach (var order in orders) { int signalCatId, parentDealId; if (!MarketOrder.GetTradeSignalFromDeal(order, out signalCatId, out parentDealId)) { continue; } TradeSignalProfit result; signalResult.TryGetValue(signalCatId, out result); if (result == null) { result = new TradeSignalProfit(); signalResult.Add(signalCatId, result); } result.openDeals.Add(order); } if (signalResult.Count == 0) { return(signalResult); } // агрегировать открытые сделки - суммарные позы по ордерам foreach (var result in signalResult.Values) { // список суммарных поз по каждому тикеру - EURUSD, ... if (result.openDeals.Count == 0) { continue; } var sumPos = PositionSummary.GetPositionSummary(quotes, result.openDeals, depoCurx, balance); result.openDeals.Clear(); foreach (var pos in sumPos) { pos.Command = MakeDealsCountString(pos.orders.Count); if (string.IsNullOrEmpty(pos.Symbol)) { continue; } result.openDeals.Add(new MarketOrder { Side = pos.Side, Symbol = pos.Symbol, Volume = pos.Volume, Comment = pos.Command, PriceEnter = pos.AveragePrice, ResultPoints = pos.ProfitInPoints, ResultDepo = pos.Profit, ResultBase = pos.ProfitInPercent }); } // суммарная поза var totalPos = sumPos.First(p => string.IsNullOrEmpty(p.Symbol)); sumPos.Remove(totalPos); result.totalOpenPosCount = sumPos.Sum(p => p.orders.Count); result.totalOpenResultDepo = sumPos.Sum(p => p.Profit); result.totalOpenResultPercent = 100 * result.totalOpenResultDepo / balance; result.totalVolumeOpenDepo = totalPos.Volume; } return(signalResult); }
/// <summary> /// таки запросить ордера /// </summary> private void CheckOrders() { Dictionary <int, List <MarketOrder> > orderDic; // получить ордера try { if (!AccountStatus.Instance.isAuthorized) { return; } var acId = AccountStatus.Instance.accountID; dealsRequestInProcess = true; try { orderDic = TradeSharpAccount.Instance.proxy.GetSignallersOpenTrades(acId); } finally { dealsRequestInProcess = false; } if (orderDic == null || orderDic.Count == 0) { return; } } catch (Exception ex) { Logger.Error("TradeSignalMonitorStream.CheckOrders() - ошибка получения ордеров", ex); return; } if (isStopping) { return; } // сравнить ордера с открытыми ордерами по счету - найти "лишние" открытые var dealsToClose = new List <MarketOrder>(); try { var orders = MarketOrdersStorage.Instance.MarketOrders; if (orders == null || orders.Count == 0) { return; } // найти в списке "лишние" ордера foreach (var order in orders) { int serviceId, parentDealId; if (!MarketOrder.GetTradeSignalFromDeal(order, out serviceId, out parentDealId)) { continue; } // найти для данного ордера "родительский" ордер List <MarketOrder> parentOrders; orderDic.TryGetValue(serviceId, out parentOrders); if (parentOrders == null) { continue; // возможно, на данныю категорию более не подписаны } if (!parentOrders.Any(o => o.ID == parentDealId)) { // у сигнальщика не найдена сделка - попытка закрыть ее if (!spareDealIds.ContainsKey(order.ID)) { // сообщить о левой сделке showMessageInUI(DateTime.Now, string.Format("Сделка {0} ({1} {2} {3}) закрыта у управляющего (сигнал #{4}) - производится закрытие", order.ID, order.Side > 0 ? "BUY" : "SELL", order.Volume, order.Symbol, serviceId)); spareDealIds.Add(order.ID, order.ID); } dealsToClose.Add(order); } } } catch (Exception ex) { Logger.Error("TradeSignalMonitorStream.CheckOrders() - ошибка сравнения ордеров", ex); } try { foreach (var deal in dealsToClose) { TryCloseDeal(deal); } } catch (Exception ex) { Logger.Error("TradeSignalMonitorStream.CheckOrders() - ошибка закрытия сделки", ex); } }