Files
zszq-trs/YLErpDAL/Modules/ExchangeTradeModule/HedgePositionCheckService.cs
T
2024-05-09 14:06:26 +08:00

389 lines
17 KiB
C#

using BaseOUDAL;
using DotNetDBF;
using YLErp.BLL;
using YLErp.Commons;
using YLErp.Models;
using YLErp.Modules.TradeRiskCalcModule;
namespace YLErp.Modules.ExchangeTradeModule
{
/// <summary>
/// 对冲交易(股票、商品期货)的系统合成持仓和读取的持仓回报数据进行比对
/// </summary>
public class HedgePositionCheckService : YLBaseService
{
public HedgePositionCheckService(OptUserInfo userInfo) : base(userInfo)
{
}
public List<DbfHedgePosition> CheckAndAddHedgePosition(UploadFileModel[] files, out List<string> diffAccounts, out List<string> unexistUmds)
{
var result = CheckHedgePosition(files, out diffAccounts, out unexistUmds);
var tradeList = new List<trade>();
foreach (var item in result)
{
var diffNotional = item.CURQTY - item.SystemNotional;
var diffTradePrice = item.DbfTradePrice - item.SystemTradePrice;
if (diffNotional != 0)
{
var hedgeTrade = new trade()
{
UnderlyingCode = item.Underlying.UnderlyingCode,
UnderlyingAssetClass = item.Underlying.UnderlyingType,
UnderlyingAssetName = item.Underlying.UnderlyingName,
UnderlyingId = item.Underlying.id,
UnderlyingInstrumentType = item.Underlying.UnderlyingInstrumentType,
TradeNumber = UniqueTimeId.GetStr(),
TradeDate = valuedateBLL.ValueDate,
StartDate = valuedateBLL.ValueDate,
MaturityDate = item.Underlying.MaturityDate,
ExerciseDate = item.Underlying.MaturityDate,
TradeStatus = ConsTrade.确认成交,
ValidState = "Valid",
AssetId = item.AssetUnit.id,
AssetBookName = item.AssetUnit.Name,
TradeType = "股票",
TradeUnit = "100股/手",
TraderId = item.AssetUnit.TraderIdsInt.FirstOrDefault(),
TraderName = UserBLL.GetNameById(item.AssetUnit.TraderIdsInt.FirstOrDefault()),
Comments = "持仓差异处理",
SpotPrice = item.Underlying.Price,
OptId = UserId,
OptName = UserName,
OptDate = DateTime.Now,
CreatorId = UserId,
CreatorName = UserName,
CreateDate = DateTime.Now
};
hedgeTrade.OriginalNotional = Math.Abs(diffNotional);
hedgeTrade.Notional = Math.Abs(diffNotional);
hedgeTrade.TradeAmount = Math.Abs(diffNotional);
hedgeTrade.Lots = Math.Abs(diffNotional) / 100;
//正常情况下diffTradePrice和diffNotional应该同号, 此时TradePrice和TradeSinglePrice均为正
//当diffTradePrice和diffNotional不同号时,说明系统原数据存在脏数据情况,此时需要补一笔TradePrice和TradeSinglePrice均为负的特殊交易,用来保持持仓成本一致
hedgeTrade.TradePrice = (diffNotional > 0 ? 1 : -1) * diffTradePrice;
hedgeTrade.TradeSinglePrice = diffTradePrice / diffNotional;
hedgeTrade.BuySell = diffNotional > 0 ? "买入" : "卖出";
tradeList.Add(hedgeTrade);
}
}
DbContext.trade.AddRange(tradeList);
DbContext.SaveChanges();
return result;
}
public List<DbfHedgePosition> CheckHedgePosition(UploadFileModel[] files, out List<string> diffAccounts, out List<string> unexistUmds)
{
unexistUmds = new List<string>();
var diffResults = new List<DbfHedgePosition>();
var dbfHedgePositions = GetHedgePositionDbfFiles(files, out diffAccounts);
var dbfHedgePositionGroups = dbfHedgePositions.GroupBy(x => new { x.BookId, x.BookName, x.SYMBOL }).Select(x => new DbfHedgePosition { BookId = x.Key.BookId, SYMBOL = x.Key.SYMBOL, BookName = x.Key.BookName, CURQTY = x.Sum(y => y.CURQTY), DbfTradePrice = x.Sum(y => y.CURQTY * y.COSTPRICE), AssetUnit = x.Select(y => y.AssetUnit).FirstOrDefault() });
var umProvider = DataCacheModule.DataCacheManager.GetUnderlyingDataSource();
foreach (var group in dbfHedgePositionGroups)
{
var req = new TradingRiskReqModel
{
Stock = true,
AssetTypes = new[] { "股票" },
BookIds = new List<int> { group.BookId ?? 0 }
};
if (unexistUmds.Contains(group.SYMBOL))
{
continue;
}
var um = umProvider.GetData(group.SYMBOL);
if (um != null)
{
group.Underlying = um;
req.UnderlyingIds = new[] { um.id };
var result = new TradingRiskReqService(OptUser).GetResult(req);
if (result != null)
{
var totalNotional = result.TradeRiskList.Sum(x => x.Notional);
var totalTradePrice = result.TradeRiskList.Sum(x => x.TradePrice);
if (group.CURQTY != totalNotional)
{
group.SystemNotional = totalNotional;
group.SystemTradePrice = totalTradePrice;
diffResults.Add(group);
}
}
else
{
group.SystemNotional = 0;
group.SystemTradePrice = 0;
diffResults.Add(group);
}
}
else
{
unexistUmds.Add(group.SYMBOL);
}
}
return diffResults;
}
public List<DbfHedgePosition> CompareExchangedOptionPosition(out string message)
{
message = string.Empty;
var valueDate = valuedateBLL.ValueDate;
var diffResults = new List<DbfHedgePosition>();
var exchangedOptionPositions = new List<DbfHedgePosition>();
var eodTradePositionStatics = DbContext.eod_trade_position_static2.Where(x => x.ValueDate == valueDate && x.TradeType == "场内期权").ToList();
var exchangeAccounts = DataCacheProvider.GetExchangeAccountDataSource().AsQueryable();
var assetUnits = DataCacheProvider.GetAssetUnitDataSource();
var underlyings = DataCacheModule.DataCacheManager.GetUnderlyingDataSource();
var exoptions = DataCacheModule.DataCacheManager.GetExchangeListOptionDataSource();
eodTradePositionStatics.ForEach(x =>
{
var exchangeAccount = exchangeAccounts.FirstOrDefault(y => y.AccountCode == x.AccountCode);
if (exchangeAccount != null)
{
var exoption = exoptions.GetData(x.UnderlyingCode);
var underlying = underlyings.GetData(exoption?.UnderlyingCode);
if (underlying != null)
{
var assetUnit = assetUnits.GetData(exchangeAccount.DefaultBookId ?? 0);
exchangedOptionPositions.Add(new DbfHedgePosition()
{
ACCT = x.AccountCode,
CURQTY = x.Volume * underlying.ContractSize * (x.PositionType == "long" ? 1 : -1),
SYMBOL = x.OptionCode,
BookId = exchangeAccount.DefaultBookId,
BookName = assetUnit != null ? assetUnit.Name : string.Empty
});
}
}
});
var exchangedOptionPositionsGroups = exchangedOptionPositions.GroupBy(x => new { x.BookId, x.BookName, x.SYMBOL }).Select(x => new DbfHedgePosition { BookId = x.Key.BookId, SYMBOL = x.Key.SYMBOL, BookName = x.Key.BookName, CURQTY = x.Sum(y => y.CURQTY) });
if (!exchangedOptionPositionsGroups.Any())
{
message = "未发现场内期权持仓数据";
}
var req = new TradingRiskReqModel
{
Stock = false,
AssetTypes = new[] { "场内期权" }
};
var result = new TradingRiskReqService(OptUser).GetResult(req);
foreach (var group in exchangedOptionPositionsGroups)
{
var tradeRiskList = result.TradeRiskList.Where(x => x.BookId == group.BookId && x.ExchangeOptionCode == group.SYMBOL);
if (tradeRiskList != null)
{
var totalNotional = tradeRiskList.Sum(x => x.Notional);
if (group.CURQTY != totalNotional)
{
group.SystemNotional = totalNotional;
diffResults.Add(group);
}
}
else
{
group.SystemNotional = 0;
diffResults.Add(group);
}
}
return diffResults;
}
public List<DbfHedgePosition> CompareCommodityFuturePosition(out string message)
{
message = string.Empty;
var valueDate = valuedateBLL.ValueDate;
var diffResults = new List<DbfHedgePosition>();
var exchangedOptionPositions = new List<DbfHedgePosition>();
var eodTradePositionStatics = DbContext.eod_trade_position_static2.Where(x => x.ValueDate == valueDate && x.TradeType == "商品期货").ToList();
var exchangeAccounts = DataCacheProvider.GetExchangeAccountDataSource().AsQueryable();
var assetUnits = DataCacheProvider.GetAssetUnitDataSource();
var underlyings = DataCacheModule.DataCacheManager.GetUnderlyingDataSource();
eodTradePositionStatics.ForEach(x =>
{
var exchangeAccount = exchangeAccounts.FirstOrDefault(y => y.AccountCode == x.AccountCode);
if (exchangeAccount != null)
{
var underlying = underlyings.GetData(x.UnderlyingCode);
if (underlying != null)
{
var assetUnit = assetUnits.GetData(exchangeAccount.DefaultBookId ?? 0);
exchangedOptionPositions.Add(new DbfHedgePosition()
{
ACCT = x.AccountCode,
CURQTY = x.Volume * underlying.ContractSize * (x.PositionType == "long" ? 1 : -1),
SYMBOL = x.UnderlyingCode,
BookId = exchangeAccount.DefaultBookId,
BookName = assetUnit != null ? assetUnit.Name : string.Empty
});
}
}
});
var exchangedOptionPositionsGroups = exchangedOptionPositions.GroupBy(x => new { x.BookId, x.BookName, x.SYMBOL }).Select(x => new DbfHedgePosition { BookId = x.Key.BookId, SYMBOL = x.Key.SYMBOL, BookName = x.Key.BookName, CURQTY = x.Sum(y => y.CURQTY) });
if (!exchangedOptionPositionsGroups.Any())
{
message = "未发现商品期货持仓数据";
}
foreach (var group in exchangedOptionPositionsGroups)
{
var req = new TradingRiskReqModel
{
Stock = false,
AssetTypes = new[] { "商品期货" },
BookIds = new List<int> { group.BookId ?? 0 }
};
var um = underlyings.GetData(group.SYMBOL);
if (um != null)
{
group.Underlying = um;
req.UnderlyingIds = new[] { um.id };
var result = new TradingRiskReqService(OptUser).GetResult(req);
if (result != null)
{
var totalNotional = result.TradeRiskList.Sum(x => x.Notional);
if (group.CURQTY != totalNotional)
{
group.SystemNotional = totalNotional;
diffResults.Add(group);
}
}
else
{
group.SystemNotional = 0;
diffResults.Add(group);
}
}
}
return diffResults;
}
private List<DbfHedgePosition> GetHedgePositionDbfFiles(UploadFileModel[] files, out List<string> diffAccounts)
{
var dbfHedgePosition = new List<DbfHedgePosition>();
diffAccounts = new List<string>();
var exchangeAccounts = DataCacheProvider.GetExchangeAccountDataSource().AsQueryable();
var assetUnits = DataCacheProvider.GetAssetUnitDataSource();
for (var i = 0; i < files.Length; i++)
{
using (var stream = files[i].OpenReadStream())
using (var dbf = new DBFReader(stream))
{
var columnCount = dbf.Fields.Length;
if (columnCount < 12)
{
throw new Exception(files[i].FileName + "文件非持仓文件,不被识别");
}
else
{
if (dbf.Fields[0].Name != "ACCT"
|| dbf.Fields[3].Name != "SYMBOL"
|| dbf.Fields[6].Name != "CURQTY"
|| dbf.Fields[11].Name != "COSTPRICE")
{
throw new Exception(files[i].FileName + "文件非持仓文件,不被识别");
}
}
var count = dbf.RecordCount;
for (var j = 0; j < count; j++)
{
var dbfRecord = dbf.NextRecord();
if (dbfRecord != null)
{
var account = dbfRecord[0].ToString().Trim();
if (diffAccounts.Contains(account))
{
continue;
}
var exchangeAccount = exchangeAccounts.FirstOrDefault(x => x.AccountCode == account);
if (exchangeAccount != null)
{
var assetUnit = assetUnits.GetData(exchangeAccount.DefaultBookId ?? 0);
double.TryParse(dbfRecord[6].ToString(), out var curqty);
double.TryParse(dbfRecord[11].ToString(), out var costPrice);
dbfHedgePosition.Add(new DbfHedgePosition()
{
ACCT = account,
CURQTY = curqty,
COSTPRICE = costPrice,
SYMBOL = dbfRecord[3].ToString(),
BookId = exchangeAccount.DefaultBookId,
BookName = assetUnit != null ? assetUnit.Name : string.Empty,
AssetUnit = assetUnit
});
}
else
{
diffAccounts.Add(account);
}
}
}
}
}
return dbfHedgePosition;
}
}
public class DbfHedgePosition
{
/// <summary>
/// 簿记账户
/// </summary>
public string ACCT { get; set; }
/// <summary>
/// 标的代码
/// </summary>
public string SYMBOL { get; set; }
/// <summary>
/// 【dbf文件】数量
/// </summary>
public double CURQTY { get; set; }
/// <summary>
/// 【dbf文件】单价
/// </summary>
public double COSTPRICE { get; set; }
/// <summary>
/// 【dbf文件】总价
/// </summary>
public double DbfTradePrice { get; set; }
/// <summary>
/// 系统数量
/// </summary>
public double SystemNotional { get; set; }
public double SystemTradePrice { get; set; }
public int? BookId { get; set; }
public string BookName { get; set; }
public underlying_manager Underlying { get; set; }
public AssetUnit AssetUnit { get; set; }
}
}