/// <summary> /// добавить маркапы и прочее шкурилово /// </summary> public static void ProcessOrderClosing(MarketOrder order, ACCOUNT account, ORDER_BILL bill, TradeSharpConnection ctx, Dictionary <string, QuoteData> quotes, string brokerCurrency) { //Logger.Info("BillingManager.ProcessOrderClosing()"); try { // перевести маркапы в валюту брокера var markupSum = bill.MarkupExit + bill.MarkupEnter; // в контрвалюте... if (markupSum != 0) { markupSum = order.Volume * markupSum; } Logger.Info("BillingManager: markupSum is " + markupSum); // перевести в валюту брокера var resultCounter = order.Side * order.Volume * (order.PriceExit.Value - order.PriceEnter); var rateCounterDepo = resultCounter == 0 ? 1 : order.ResultDepo / resultCounter; // валюта брокера к контрвалюте var rateCounterBroker = rateCounterDepo; Logger.Info("BillingManager: rateCounterDepo is " + rateCounterDepo); if (account.Currency != brokerCurrency) { // пример: позиция EURCAD, валюта брокера USD // надо получить курс CADUSD var markupBroker = (float)markupSum; string errorStr; var resultedMarkup = DalSpot.Instance.ConvertToTargetCurrency(order.Symbol, false, brokerCurrency, markupBroker, quotes, out errorStr, true); if (!resultedMarkup.HasValue) { Logger.ErrorFormat("BillingManager.ProcessOrderClosing - невозможно перевести профит по {0} в {1}: {2}", order.Symbol, brokerCurrency, errorStr); return; } markupBroker = (float)resultedMarkup.Value; rateCounterBroker = (float)(markupBroker / markupSum); markupSum = markupBroker; } else { markupSum *= rateCounterBroker; } bill.MarkupBroker = markupSum; bill.ProfitBroker = resultCounter * rateCounterBroker; Logger.InfoFormat("BillingManager: MarkupBroker: {0}, ProfitBroker: {1}", bill.MarkupBroker, bill.ProfitBroker); // сохранить билль ctx.Entry(bill).State = EntityState.Modified; Logger.InfoFormat("BillingManager:OK"); } catch (Exception ex) { Logger.Error("BillingManager.ProcessOrderClosing() - ошибка редактирования счета", ex); } }
public bool CloseOrder(MarketOrder order, decimal price, PositionExitReason exitReason) { using (var ctx = DatabaseContext.Instance.Make()) { var account = ctx.ACCOUNT.FirstOrDefault(ac => ac.ID == order.AccountID); if (account == null) { Logger.ErrorFormat("Закрытие ордера #{0}: невозможно прочитать данные счета ({1})", order.ID, order.AccountID); return(false); } // провести ордер через биллинг ORDER_BILL bill = null; if (order.State == PositionState.Opened) { bill = BillingManager.ProcessPriceForOrderClosing(order, LinqToEntity.DecorateAccount(account), ctx); } // посчитать результат // и обновить объект order.State = PositionState.Closed; order.PriceExit = (float?)price; var deltaAbs = order.Side * (order.PriceExit.Value - order.PriceEnter); order.ResultPoints = DalSpot.Instance.GetPointsValue(order.Symbol, deltaAbs); var deltaDepo = deltaAbs * order.Volume; var quotes = QuoteStorage.Instance.ReceiveAllData(); string errorStr; var resultedDepo = DalSpot.Instance.ConvertToTargetCurrency(order.Symbol, false, account.Currency, deltaDepo, quotes, out errorStr, false); if (!resultedDepo.HasValue) { Logger.ErrorFormat("#{0} ({1} {2}{3}, {4:f1} пп): ошибка расчета прибыли в валюте депозита - {5}", order.ID, order.Side > 0 ? "B" : "S", order.Symbol, order.Volume, order.ResultPoints, errorStr); return(false); } order.ResultDepo = (float)resultedDepo.Value; //order.Swap = (float)swap; order.ExitReason = exitReason; order.TimeExit = DateTime.Now; var posClosed = LinqToEntity.UndecorateClosedPosition(order); POSITION pos = null; try { // занести ордер в список закрытых позиций (создать новую запись "истории") ctx.POSITION_CLOSED.Add(posClosed); // удалить открытый ордер pos = ctx.POSITION.FirstOrDefault(p => p.ID == order.ID); if (pos == null) { Logger.ErrorFormat("CloseOrder - позиция {0} не найдена", order.ID); ServiceManagerClientManagerProxy.Instance.CloseOrderResponse(null, RequestStatus.ServerError, "crudsav"); return(false); } ctx.POSITION.Remove(pos); // посчитать профиты if (bill != null) { BillingManager.ProcessOrderClosing(order, account, bill, ctx, quotes, brokerRepository.BrokerCurrency); } // сохранить изменения ctx.SaveChanges(); // обновить баланс var resultAbs = Math.Abs(order.ResultDepo); if (!UpdateAccountBalance(ctx, account, (decimal)resultAbs, order.ResultDepo >= 0 ? BalanceChangeType.Profit : BalanceChangeType.Loss, string.Format("результат сделки #{0}", posClosed.ID), DateTime.Now, order.ID)) { Logger.ErrorFormat("Не удалось применить обновление баланса #{0}", posClosed.ID); } } catch (OptimisticConcurrencyException ex) { Logger.Error("CloseOrder - OptimisticConcurrencyException", ex); ctx.Entry(posClosed).State = EntityState.Modified; ((IObjectContextAdapter)ctx).ObjectContext.Refresh(RefreshMode.ClientWins, posClosed); if (pos != null) { ctx.Entry(pos).State = EntityState.Modified; ((IObjectContextAdapter)ctx).ObjectContext.Refresh(RefreshMode.ClientWins, pos); } ctx.SaveChanges(); } catch (Exception ex) { Logger.ErrorFormat("Ошибка закрытия позиции {0} (счет #{1}) (фиксация в БД): {2}", order.ID, order.AccountID, ex); ServiceManagerClientManagerProxy.Instance.CloseOrderResponse(null, RequestStatus.ServerError, "crudsave"); return(false); } } // уведомить клиента ServiceManagerClientManagerProxy.Instance.CloseOrderResponse(order, RequestStatus.OK, ""); // разослать торговый сигнал MakeOrderClosedSignal(order.AccountID, order.ID, (float)price); return(true); }