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
{
///
/// Class FloatPLExpressions.
///
public class FloatPLExpressions
{
///
/// 保留盈亏的小数位数
///
public const int c_figures = 2;
///
/// 计算持仓单的浮动盈亏(没取到交易所时计算使用持仓均价计算)
///
/// 持仓单
/// 计算的盈亏
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);
}
///
/// 计算持仓单的盈亏汇总
///
/// 持仓单
///
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);
}
///
/// 计算全额商品持仓市值
///
/// 持仓单
/// 持仓市值
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);
}
///
/// 计算平仓单的盈亏汇总
///
/// 持仓单
///
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);
}
///
/// 可取资金
///
/// 阀值计算
/// 可取资金数量
public static decimal SetUseAmount(List 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);
}
///
/// 计算持仓汇总浮动盈亏(默认计算使用持仓均价计算)}
///
/// 持仓汇总
/// 计算的盈亏
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;
}
/// 计算全额浮动盈亏或保证金浮动盈亏
///
///
/// 全额浮动盈亏
/// 保证金浮动盈亏
public static void CalcFullPayPLWithSumPL(ObservableCollection 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
///
/// 更新账户的总浮动盈亏
///
/// System.Decimal.
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;
}
}
}
///
/// Calculates the float pl by quote goods.
///
/// The quote goods.
/// The holding summaries.
public static void CalcFloatPLByQuoteGoods(QuoteGoods quoteGoods, ObservableCollection holdingSummaries)
{
if (quoteGoods == null || holdingSummaries == null || !holdingSummaries.Any()) return;
foreach (var item in holdingSummaries)
{
CalcFloatPL(quoteGoods, item, false);
}
}
///
/// Calculates the float pl.
///
/// The holding summaries.
public static void CalcFloatPL(ObservableCollection 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);
}
}
///
/// Updates the float pl. MTP2.0 统一计算持仓盈亏
///
/// The quote goods.
///
/// Calculates the float pl.
///
/// The quote goods.
/// The holding summary.
/// 是否需要算汇率
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
}
}