389 lines
17 KiB
C#
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; }
|
|
}
|
|
}
|