| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441 |
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using Muchinfo.MTPClient.Data.Model;
- using Muchinfo.MTPClient.Infrastructure.Cache;
- using Muchinfo.MTPClient.Data.Enums;
- using Muchinfo.MTPClient.Data.Model.Account;
- using Muchinfo.MTPClient.Infrastructure.Utilities;
- using System;
- using System.Linq;
- namespace Muchinfo.MTPClient.Infrastructure.Helpers
- {
- /// <summary>
- /// Class FloatPLExpressions.
- /// </summary>
- public class FloatPLExpressions
- {
- /// <summary>
- /// 保留盈亏的小数位数
- /// </summary>
- public const int c_figures = 2;
- /// <summary>
- /// 计算持仓单的浮动盈亏(没取到交易所时计算使用持仓均价计算)
- /// </summary>
- /// <param name="openOrder">持仓单</param>
- /// <returns>计算的盈亏</returns>
- public static decimal OrderDetailFloatPL(HoldingOrder openOrder, QuoteGoods goods)
- {
- decimal result = 0m;
- //var exchange =
- // CacheManager.CacheExchanges.FirstOrDefault(
- // (exchangeItem) => exchangeItem.ExchangeId == UserManager.CurrentTradeAccount.ExchangeId);
- var orderFlag = (openOrder.Direction == Direction.Ask) ? -1 : 1;
- if (goods == null || openOrder.ClosePrice <= 0)
- {
- return result;
- }
- var makeGoodsGroup = CacheManager.CacheMarketsGroups.FirstOrDefault((goodsGroup) => goodsGroup.MarketID == goods.GoodsParameters.SortId);
- if (makeGoodsGroup != null)
- {
- #region MTP2.0 注销
- //var reckonMode = makeGoodsGroup.ReckonMode;
- //switch (reckonMode)
- //{
- // case ReckonModeType.HadDebat:
- // result = (openOrder.ClosePrice * openOrder.Lot * orderFlag
- // * goods.GoodsParameters.AgreeUnit *
- // (goods.GoodsParameters.ReckonRate == 0
- // ? 1
- // : goods.GoodsParameters.ReckonRate)) - (
- // openOrder.OpenPrice * openOrder.Lot * orderFlag
- // * goods.GoodsParameters.AgreeUnit *
- // (goods.GoodsParameters.ReckonRate == 0
- // ? 1
- // : goods.GoodsParameters.ReckonRate));
- // break;
- // case ReckonModeType.NoDebat:
- // result = (openOrder.ClosePrice * openOrder.Lot * orderFlag
- // * goods.GoodsParameters.AgreeUnit *
- // (goods.GoodsParameters.ReckonRate == 0
- // ? 1
- // : goods.GoodsParameters.ReckonRate))
- // - (openOrder.HoldingPrice * openOrder.Lot * orderFlag
- // * goods.GoodsParameters.AgreeUnit *
- // (goods.GoodsParameters.ReckonRate == 0
- // ? 1
- // : goods.GoodsParameters.ReckonRate));
- // break;
- // default:
- // break;
- //}
- #endregion
- }
- else
- {
- result = (openOrder.ClosePrice - openOrder.HoldingPrice) * openOrder.Lot * orderFlag
- * goods.GoodsParameters.AgreeUnit *
- (goods.GoodsParameters.ReckonRate == 0
- ? 1
- : goods.GoodsParameters.ReckonRate);
- }
- return Math.Round(result, c_figures, MidpointRounding.AwayFromZero);
- }
- /// <summary>
- /// 计算持仓单的盈亏汇总
- /// </summary>
- /// <param name="openOrder">持仓单</param>
- /// <returns></returns>
- public static decimal CalcOrderDetailSumPL(HoldingOrder openOrder)
- {
- decimal result = 0m;
- if (UserManager.CurrentTradeAccount == null || openOrder.QuoteGoods == null ||
- openOrder.QuoteGoods.GoodsParameters == null || openOrder.ClosePrice <= 0)
- {
- return result;
- }
- var orderFlag = (openOrder.Direction == Direction.Ask) ? -1 : 1;
- result = (openOrder.ClosePrice * openOrder.Lot * orderFlag
- * openOrder.QuoteGoods.GoodsParameters.AgreeUnit *
- (openOrder.QuoteGoods.GoodsParameters.ReckonRate == 0
- ? 1
- : openOrder.QuoteGoods.GoodsParameters.ReckonRate)) - (
- openOrder.OpenPrice * openOrder.Lot * orderFlag
- * openOrder.QuoteGoods.GoodsParameters.AgreeUnit *
- (openOrder.QuoteGoods.GoodsParameters.ReckonRate == 0
- ? 1
- : openOrder.QuoteGoods.GoodsParameters.ReckonRate));
- return Math.Round(result, c_figures, MidpointRounding.AwayFromZero);
- }
- /// <summary>
- /// 计算全额商品持仓市值
- /// </summary>
- /// <param name="openOrder">持仓单</param>
- /// <returns>持仓市值</returns>
- public static decimal CalcHoldAmount(HoldingOrder openOrder, QuoteGoods goods)
- {
- decimal result = 0m;
- if (goods == null || goods.GoodsParameters == null)
- {
- return result;
- }
- else if (goods.GoodsParameters.MoneyMode ==
- eMoneyMode.MONEYMODE_MARGIN)
- {
- return result;
- }
- else if (openOrder.ClosePrice <= 0) ////取不到昨收时,最新价时使用持仓金额
- {
- return openOrder.HoldAmount;
- }
- result = (openOrder.ClosePrice * openOrder.Lot
- * goods.GoodsParameters.AgreeUnit *
- (goods.GoodsParameters.ReckonRate == 0
- ? 1
- : goods.GoodsParameters.ReckonRate));
- return Math.Round(result, c_figures, MidpointRounding.AwayFromZero);
- }
- /// <summary>
- /// 计算平仓单的盈亏汇总
- /// </summary>
- /// <param name="openOrder">持仓单</param>
- /// <returns></returns>
- public static decimal CalcCloseOrderSumPL(CloseOrder closeOrder)
- {
- decimal result = 0m;
- var orderFlag = (closeOrder.Direction == Direction.Ask) ? 1 : -1;
- result = (closeOrder.ClosePrice * closeOrder.Lot * orderFlag
- * closeOrder.AgreeUnit) - (closeOrder.OpenPrice * closeOrder.Lot * orderFlag
- * closeOrder.AgreeUnit);
- return Math.Round(result, c_figures, MidpointRounding.AwayFromZero);
- }
- /// <summary>
- /// 可取资金
- /// </summary>
- /// <param name="ratios">阀值计算</param>
- /// <returns>可取资金数量</returns>
- public static decimal SetUseAmount(List<OutMoneyThresholdRatio> ratios)
- {
- decimal sum = 0;
- if (UserManager.CurrentTradeAccount != null &&
- UserManager.CurrentTradeAccount.FundsAccounts != null &&
- UserManager.CurrentTradeAccount.FundsAccounts.Any())
- {
- var ratiosThreshold = 0m;
- var currentNet = UserManager.CurrentTradeAccount.FundsAccounts[0].CurrentNetWorth;
- if (ratios != null && ratios.Any() && currentNet > 0)
- {
- for (int i = 0; i < ratios.Count; i++) //阈值比例计算的阈值=净值*阈值比例
- {
- if (i == ratios.Count - 1)
- {
- ratiosThreshold = ratios[i].ThresholdRatio * currentNet;
- break;
- }
- else if (ratios[i].NetWorth <= currentNet && ratios[i + 1].NetWorth > currentNet)
- {
- ratiosThreshold = ratios[i].ThresholdRatio * currentNet;
- break;
- }
- }
- }
- var threshold = Math.Max(UserManager.CurrentTradeAccount.FundsAccounts[0].OutThreshold,
- UserManager.CurrentTradeAccount.FundsAccounts[0].MincurrentBalance); ////最低保证金,仓单冲抵最低保证金
- threshold = Math.Max(threshold, ratiosThreshold); //5. 出金阈值=max(最低保证金+仓单冲抵最低保证金,阈值比例计算的阈值)
- threshold = Math.Max(threshold, UserManager.CurrentTradeAccount.FundsAccounts[0].ManualFreeze); //人工冻结
- sum = UserManager.CurrentTradeAccount.FundsAccounts[0].Balance; ///可用
- sum += UserManager.CurrentTradeAccount.FundsAccounts[0].OutAmount;
- sum -= UserManager.CurrentTradeAccount.FundsAccounts[0].OutAmountFreeze;
- var avail = UserManager.CurrentTradeAccount.FundsAccounts[0].ManualFreeze + UserManager.CurrentTradeAccount.FundsAccounts[0].AvailMargin; ///(冻结汇总减了一次ManualFreeze)
- if (UserManager.CurrentTradeAccount.FundsAccounts[0].IsAllowInMoney == 1) ////当天入金可出
- {
- sum = Math.Min(sum + UserManager.CurrentTradeAccount.FundsAccounts[0].InAmount, avail);
- }
- else
- {
- sum = Math.Min(sum, avail);
- }
- sum -= threshold; ///可出-出金阈值
- }
- sum = sum < 0 ? 0 : sum;
- return Math.Round(sum, 2, MidpointRounding.AwayFromZero);
- }
- /// <summary>
- /// 计算持仓汇总浮动盈亏(默认计算使用持仓均价计算)}
- /// </summary>
- /// <param name="holdingSummary">持仓汇总</param>
- /// <returns>计算的盈亏</returns>
- public static decimal PositionFloatPL(HoldingSummary holdingSummary)
- {
- decimal result = 0m;
- if (UserManager.CurrentTradeAccount == null || holdingSummary.QuoteGoods == null ||
- holdingSummary.QuoteGoods.GoodsParameters == null)
- {
- return result;
- }
- var makeGoodsGroup = CacheManager.CacheMarketsGroups.FirstOrDefault((goodsGroup) => goodsGroup.MarketID == holdingSummary.QuoteGoods.GoodsParameters.SortId);
- var orderFlag = (holdingSummary.Direction == Direction.Ask) ? -1 : 1;
- if (makeGoodsGroup != null)
- {
- #region MTP2.0 注销
- //var reckonMode = makeGoodsGroup.ReckonMode;
- //switch (reckonMode)
- //{
- // case ReckonModeType.HadDebat:
- // result = (holdingSummary.ClosePrice - holdingSummary.AVGPrice) * holdingSummary.Lot * orderFlag
- // * holdingSummary.QuoteGoods.GoodsParameters.AgreeUnit;
- // break;
- // case ReckonModeType.NoDebat:
- // result = (holdingSummary.ClosePrice - holdingSummary.HoldingAVGPrice) * holdingSummary.Lot * orderFlag
- // * holdingSummary.QuoteGoods.GoodsParameters.AgreeUnit;
- // break;
- // default:
- // break;
- //}
- #endregion
- }
- else
- {
- result = (holdingSummary.ClosePrice - holdingSummary.HoldingAVGPrice) * holdingSummary.Lot * orderFlag
- * holdingSummary.QuoteGoods.GoodsParameters.AgreeUnit;
- }
- return result;
- }
- /// 计算全额浮动盈亏或保证金浮动盈亏
- /// </summary>
- /// <param name="holders"></param>
- /// <param name="payPL">全额浮动盈亏</param>
- /// <param name="marginPL">保证金浮动盈亏</param>
- public static void CalcFullPayPLWithSumPL(ObservableCollection<HoldingOrder> holders, out decimal payPL, out decimal marginPL)
- {
- marginPL = 0;
- payPL = 0;
- foreach (var holdingOrder in holders)
- {
- if (holdingOrder.QuoteGoods != null && holdingOrder.QuoteGoods.GoodsParameters.MoneyMode ==
- eMoneyMode.MONEYMODE_PAY)
- {
- payPL += holdingOrder.PLFloat;
- }
- else
- {
- marginPL += holdingOrder.PLFloat;
- }
- }
- }
- #region MTP2.0
- /// <summary>
- /// 更新账户的总浮动盈亏
- /// </summary>
- /// <returns>System.Decimal.</returns>
- public static void UpdateAccountTotalFloatPL()
- {
- if (UserManager.CurrentTradeAccount.FundsAccounts != null &&
- UserManager.CurrentTradeAccount.FundsAccounts.Count > 0)
- {
- foreach (var accountId in UserManager.CurrentTradeAccount.FundsAccountIds)
- {
- decimal sum = 0;
- var fundsAccount = UserManager.CurrentTradeAccount.FundsAccounts.FirstOrDefault(z => z.AccountId == accountId);
- if (fundsAccount == null) continue;
- //查询持仓汇总缓存-通用查询回来的对象
- var holders = UserManager.GetHoldSummaries(accountId);
- if (holders == null) continue;
- foreach (var item in holders)
- {
- var quoteGoods = CacheManager.CacheGoodsBaseInfos.FirstOrDefault(p => p.GoodsId == item.GoodsId);
- CalcFloatPL(quoteGoods, item, true);
- sum += item.PLFloatWithRate;
- }
- fundsAccount.FloatPL = sum;
- }
- }
- }
- /// <summary>
- /// Calculates the float pl by quote goods.
- /// </summary>
- /// <param name="quoteGoods">The quote goods.</param>
- /// <param name="holdingSummaries">The holding summaries.</param>
- public static void CalcFloatPLByQuoteGoods(QuoteGoods quoteGoods, ObservableCollection<HoldingSummary> holdingSummaries)
- {
- if (quoteGoods == null || holdingSummaries == null || !holdingSummaries.Any()) return;
- foreach (var item in holdingSummaries)
- {
- CalcFloatPL(quoteGoods, item, false);
- }
- }
- /// <summary>
- /// Calculates the float pl.
- /// </summary>
- /// <param name="holdingSummaries">The holding summaries.</param>
- public static void CalcFloatPL(ObservableCollection<HoldingSummary> holdingSummaries)
- {
- if (holdingSummaries == null || !holdingSummaries.Any()) return;
- foreach (var item in holdingSummaries)
- {
- var quoteGoods = CacheManager.CacheGoodsBaseInfos.FirstOrDefault(p => p.GoodsId == item.GoodsId);
- CalcFloatPL(quoteGoods, item, false);
- }
- }
- /// <summary>
- /// Updates the float pl. MTP2.0 统一计算持仓盈亏
- /// </summary>
- /// <param name="quoteGoods">The quote goods.</param>
- /// <summary>
- /// Calculates the float pl.
- /// </summary>
- /// <param name="quoteGoods">The quote goods.</param>
- /// <param name="holdingSummary">The holding summary.</param>
- /// <param name="needRate">是否需要算汇率</param>
- private static void CalcFloatPL(QuoteGoods quoteGoods, HoldingSummary holdingSummary, Boolean needRate = false)
- {
- if (quoteGoods == null || holdingSummary == null || holdingSummary.GoodsId != quoteGoods.GoodsId) return;
- if (needRate)
- {
- //// 计算汇率,主要用于资金账户盈亏计算
- //var tradeRateConfig = UserManager.TradeRateTmpConfigs.FirstOrDefault(z => z.AccountId == holdingSummary.AccountId && z.OriCurrencyId == quoteGoods.Currencyid);
- //// 如果用当前资金账户找不到,再尝试用所属母账户获取汇率配置
- //if (tradeRateConfig == null && UserManager.CurrentTradeAccount.FundsAccounts.Count > 0 && UserManager.CurrentTradeAccount.FundsAccounts[0].ParentAccountID != 0)
- //{
- // tradeRateConfig = UserManager.TradeRateTmpConfigs.FirstOrDefault(z => z.AccountId == UserManager.CurrentTradeAccount.FundsAccounts[0].ParentAccountID && z.OriCurrencyId == quoteGoods.Currencyid);
- //}
- //// 如果还是找不到,则再尝试从外部汇率模版配置表获取
- //tradeRateConfig = UserManager.ExtenalTradeRateTmpConfigs.FirstOrDefault(z => z.AccountId == holdingSummary.AccountId && z.OriCurrencyId == quoteGoods.Currencyid);
- //if (tradeRateConfig == null && UserManager.CurrentTradeAccount.FundsAccounts.Count > 0 && UserManager.CurrentTradeAccount.FundsAccounts[0].ParentAccountID != 0)
- //{
- // tradeRateConfig = UserManager.ExtenalTradeRateTmpConfigs.FirstOrDefault(z => z.AccountId == UserManager.CurrentTradeAccount.FundsAccounts[0].ParentAccountID && z.OriCurrencyId == quoteGoods.Currencyid);
- //}
- // 从新的资金账户汇率查询中获取汇率
- TradeRateTmpConfig tradeRateConfig = null;
- if (UserManager.TaAccountExchangeRateConfigs != null)
- {
- tradeRateConfig = UserManager.TaAccountExchangeRateConfigs.FirstOrDefault(z => z.AccountId == holdingSummary.AccountId && z.OriCurrencyId == quoteGoods.Currencyid);
- }
- var tradeRate = tradeRateConfig == null ? 1 : tradeRateConfig.ExchangeRate;
- holdingSummary.QuoteGoods = quoteGoods;
- holdingSummary.LatestPrice = holdingSummary.QuoteGoods.CurrentPrice != 0 ? holdingSummary.QuoteGoods.CurrentPrice : holdingSummary.QuoteGoods.LastClose;
- if (holdingSummary.Lot > 0 && holdingSummary.LatestPrice != 0)
- {
- if (holdingSummary.Direction == Direction.Ask)
- holdingSummary.PLFloatWithRate = (holdingSummary.CurHolderAmount - (holdingSummary.Lot * holdingSummary.LatestPrice * holdingSummary.AgreeUnit)) * tradeRate;
- else if (holdingSummary.Direction == Direction.Bid)
- holdingSummary.PLFloatWithRate = ((holdingSummary.Lot * holdingSummary.LatestPrice * holdingSummary.AgreeUnit) - holdingSummary.CurHolderAmount) * tradeRate;
- }
- }
- else
- {
- // 不计算汇率,用于持仓汇总盈亏计算
- holdingSummary.QuoteGoods = quoteGoods;
- holdingSummary.LatestPrice = holdingSummary.QuoteGoods.CurrentPrice != 0 ? holdingSummary.QuoteGoods.CurrentPrice : holdingSummary.QuoteGoods.LastClose;
- if (holdingSummary.Lot > 0 && holdingSummary.LatestPrice != 0)
- {
- if (holdingSummary.Direction == Direction.Ask)
- holdingSummary.PLFloat = holdingSummary.CurHolderAmount - (holdingSummary.Lot * holdingSummary.LatestPrice * holdingSummary.AgreeUnit);
- else if (holdingSummary.Direction == Direction.Bid)
- holdingSummary.PLFloat = (holdingSummary.Lot * holdingSummary.LatestPrice * holdingSummary.AgreeUnit) - holdingSummary.CurHolderAmount;
- // 错误 #92030 计算开仓浮动盈亏
- holdingSummary.OpenProfitLoss = (holdingSummary.LatestPrice - holdingSummary.OpenAvaPrice) * holdingSummary.AvailQty * holdingSummary.AgreeUnit * (holdingSummary.Direction == Direction.Ask ? -1 : 1);
- }
- }
- }
- #endregion
- #region HoldingOrder20的持仓盈亏计算方式
- public static void CalcPl(HoldingOrder20 order20, QuoteGoods quoteGoods)
- {
- if (order20 == null || quoteGoods == null)
- {
- return;
- }
- // 不计算汇率,用于持仓汇总盈亏计算
- order20.QuoteGoods = quoteGoods;
- order20.LastPrice = order20.QuoteGoods.CurrentPrice != 0 ? order20.QuoteGoods.CurrentPrice : order20.QuoteGoods.LastClose;
- if (order20.HolderQty > 0 && order20.LastPrice != 0)
- {
- if (order20.Direction == Direction.Ask)
- order20.ProfitLoss = order20.HolderAmount - (order20.HolderQty * order20.LastPrice * order20.QuoteGoods.AgreeUnit);
- else if (order20.Direction == Direction.Bid)
- order20.ProfitLoss = (order20.HolderQty * order20.LastPrice * order20.QuoteGoods.AgreeUnit) - order20.HolderAmount;
- }
- }
- #endregion
- }
- }
|