Files
zszq-trs/YLErpWeb/Controllers/margin_template_v2Controller.cs
T

745 lines
37 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using YLErp.BLL;
using YLErp.Configuration;
using YLErp.DBModels;
using YLErp.Enums;
using YLErp.Modules.MarginModule;
namespace YLErp.Web.Controllers
{
public class margin_template_v2Controller : BaseController
{
[MyAuthorize("基础参数管理-预付金模板V2")]
public ActionResult margin_template_v2List()
{
if (PS.Config.Company != CompanyEnum.广发商贸)
{
return View();
}
return Redirect("margin_template_v2ClientList");
}
[MyAuthorize("基础参数管理-预付金模板V2")]
public ActionResult margin_template_v2DefaultList()
{
return View();
}
[MyAuthorize("基础参数管理-预付金模板V2")]
public ActionResult margin_template_v2ClientList()
{
return View();
}
[HttpPost]
public JsonResult margin_template_v2GroupQuery(margin_template_v2Req req)
{
req.IsDefault = false;
req.IsForClient = false;
var sList = new MarginTemplateService(CurUser).SearchMarginTemplateV2List(req);
return Json(sList);
}
[HttpPost]
public JsonResult margin_template_v2GroupDefaultQuery(margin_template_v2Req req)
{
req.IsDefault = true;
req.IsForClient = false;
var sList = new MarginTemplateService(CurUser).SearchMarginTemplateV2List(req);
return Json(sList);
}
[HttpPost]
public JsonResult margin_template_v2GroupClientQuery(margin_template_v2Req req)
{
req.IsDefault = true;
req.IsForClient = true;
var sList = new MarginTemplateService(CurUser).SearchMarginTemplateV2List(req);
return Json(sList);
}
public ActionResult margin_template_v2DefaultEdit(string enid)
{
if (string.IsNullOrEmpty(enid) || enid == "0")
{
return View(new margin_template_v2() { ValueDate = valuedateBLL.ValueDate, RuleType = (int)MarginRuleTypeEnum.无预付金, Comments = "预付金占用为零。", IsValid = true });
}
var intid = DecryptInt(enid);
var r = yldb.margin_template_v2.AsNoTracking().FirstOrDefault(n => n.id == intid);
if (r == null)
{
return ShowError("数据不存在");
}
r.Details = yldb.margin_template_detail.Where(x => x.MarginTemplateId == r.id).OrderBy(x => x.ValueDate).ToList();
if (!r.Details.Any())
{
r.Details.Add(new margin_template_detail() { ValueDate = new DateTime(2020, 1, 1) });
}
r.LatestValueDate = r.Details.LastOrDefault()?.ValueDate;
return View(r);
}
public ActionResult margin_template_v2DefaultCopy(string enid)
{
var intid = DecryptInt(enid);
var r = yldb.margin_template_v2.AsNoTracking().FirstOrDefault(n => n.id == intid);
if (r == null)
{
return ShowError("数据不存在");
}
r.Details = yldb.margin_template_detail.Where(x => x.MarginTemplateId == r.id).OrderBy(x => x.ValueDate).ToList();
r.id = 0;
if (!r.Details.Any())
{
r.Details.Add(new margin_template_detail() { ValueDate = new DateTime(2020, 1, 1) });
}
else
{
r.Details.ForEach(x =>
{
x.MarginTemplateId = 0;
x.id = 0;
});
}
r.LatestValueDate = r.Details.LastOrDefault()?.ValueDate;
return View("margin_template_v2DefaultEdit", r);
}
public ActionResult margin_template_v2ClientEdit(string enid)
{
if (string.IsNullOrEmpty(enid) || enid == "0")
{
if (PS.Config.Company == CompanyEnum.广发商贸)
{
return View(new margin_template_v2() { ValueDate = new DateTime(2020, 1, 1), RuleType = (int)MarginRuleTypeEnum.默认预付金规则, Comments = "考虑了14种场景下的Span算法与Delta算法比较的通用预付金规则,该规则可以调整Span涨跌幅度", IsValid = true });
}
//预付金模板V2迁移:本部署(TRS)可选规则只有 无预付金/区间追保结构,新模板默认无预付金。
//原始代码如下(如需恢复,用注释行整行替换下面的 return):
//return View(new margin_template_v2() { ValueDate = new DateTime(2020, 1, 1), RuleType = (int)MarginRuleTypeEnum.触发条件预付金规则1, Comments = "预付金占用为成交名义本金的固定比例,加标的跌幅的市值(跌幅达到一定条件触发)", IsValid = true });
return View(new margin_template_v2() { ValueDate = new DateTime(2020, 1, 1), RuleType = (int)MarginRuleTypeEnum.无预付金, Comments = "预付金占用为零。", IsValid = true });
}
var intid = DecryptInt(enid);
var r = yldb.margin_template_v2.AsNoTracking().FirstOrDefault(n => n.id == intid);
if (r == null)
{
return ShowError("数据不存在");
}
r.Details = yldb.margin_template_detail.Where(x => x.MarginTemplateId == r.id).OrderBy(x => x.ValueDate).ToList();
if (!r.Details.Any())
{
r.Details.Add(new margin_template_detail() { ValueDate = new DateTime(2020, 1, 1) });
}
r.LatestValueDate = r.Details.LastOrDefault()?.ValueDate;
return View(r);
}
public ActionResult margin_template_v2ClientCopy(string enid)
{
var intid = DecryptInt(enid);
var r = yldb.margin_template_v2.AsNoTracking().FirstOrDefault(n => n.id == intid);
if (r == null)
{
return ShowError("数据不存在");
}
r.Details = yldb.margin_template_detail.Where(x => x.MarginTemplateId == r.id).OrderBy(x => x.ValueDate).ToList();
r.id = 0;
if (!r.Details.Any())
{
r.Details.Add(new margin_template_detail() { ValueDate = new DateTime(2020, 1, 1) });
}
else
{
r.Details.ForEach(x =>
{
x.MarginTemplateId = 0;
x.id = 0;
});
}
r.LatestValueDate = r.Details.LastOrDefault()?.ValueDate;
return View("margin_template_v2ClientEdit", r);
}
public ActionResult margin_template_v2Edit(string enid)
{
if (string.IsNullOrEmpty(enid) || enid == "0")
{
return View(new margin_template_v2() { ValueDate = new DateTime(2020, 1, 1), RuleType = (int)MarginRuleTypeEnum.无预付金, Comments = "预付金占用为零。", IsValid = true });
}
var intid = DecryptInt(enid);
var r = yldb.margin_template_v2.AsNoTracking().FirstOrDefault(n => n.id == intid);
if (r == null)
{
return ShowError("数据不存在");
}
r.Details = yldb.margin_template_detail.Where(x => x.MarginTemplateId == r.id).OrderBy(x => x.ValueDate).ToList();
if (!r.Details.Any())
{
r.Details.Add(new margin_template_detail() { ValueDate = new DateTime(2020, 1, 1) });
}
r.LatestValueDate = r.Details.LastOrDefault()?.ValueDate;
return View(r);
}
public ActionResult margin_template_v2Copy(string enid)
{
var intid = DecryptInt(enid);
var r = yldb.margin_template_v2.AsNoTracking().FirstOrDefault(n => n.id == intid);
if (r == null)
{
return ShowError("数据不存在");
}
r.Details = yldb.margin_template_detail.Where(x => x.MarginTemplateId == r.id).OrderBy(x => x.ValueDate).ToList();
r.id = 0;
if (!r.Details.Any())
{
r.Details.Add(new margin_template_detail() { ValueDate = new DateTime(2020, 1, 1) });
}
else
{
r.Details.ForEach(x =>
{
x.MarginTemplateId = 0;
x.id = 0;
});
}
r.LatestValueDate = r.Details.LastOrDefault()?.ValueDate;
return View("margin_template_v2Edit", r);
}
public JsonResult margin_template_v2Delete(string enid)
{
var intid = DecryptInt(enid);
var tradeMarginTemplates = yldb.trade_margin_template.Where(x => x.MarginTemplateId == intid);
if (tradeMarginTemplates.Any())
{
throw new Exception("该自定义预付金规则已经有交易使用了,不可被删除");
}
else
{
var marginTemplate = yldb.margin_template_v2.Find(intid);
if (marginTemplate != null)
{
yldb.margin_template_v2.Remove(marginTemplate);
yldb.SaveChanges();
}
}
return JsonSuccess("删除成功");
}
[HttpPost]
public JsonResult saveMarginTemplateV2(margin_template_v2 marginTemplate)
{
try
{
if (string.IsNullOrEmpty(marginTemplate.TradeTypes))
{
throw new Exception("默认规则的适用结构不能为空");
}
if (yldb.margin_template_v2.Any(x => x.id != marginTemplate.id && x.Name == marginTemplate.Name && x.IsDefault == marginTemplate.IsDefault && x.IsForClient == marginTemplate.IsForClient))
{
throw new Exception("不能取重复的预付金名称");
}
if (marginTemplate.IsDefault && !marginTemplate.IsForClient && marginTemplate.IsValid)
{
//一套规则多套默认参数的互斥验证
if (marginTemplate.DefaultParameterType != 0)
{
//验证不同规则是否已经存在该交易类型
var marginTemplateDefault = yldb.margin_template_v2.Where(x => x.id != marginTemplate.id && x.IsDefault && x.IsValid && !x.IsForClient && x.RuleType != marginTemplate.RuleType && x.ValueDate == marginTemplate.ValueDate);
var existTradeTypes = marginTemplateDefault.Select(x => x.TradeTypes).ToList();
var tradeTypes = new List<string>();
existTradeTypes.ForEach(x => tradeTypes.AddRange(x.Split(',')));
//验证相同规则相同的默认参数类型,是否包含相同的适用结构
var sameRuleParameterRecord = yldb.margin_template_v2.FirstOrDefault(x => x.id != marginTemplate.id && x.IsDefault && x.IsValid && !x.IsForClient && x.RuleType == marginTemplate.RuleType && x.DefaultParameterType == marginTemplate.DefaultParameterType && (x.BuySellType & marginTemplate.BuySellType) > 0 && (x.MarginScenarios & marginTemplate.MarginScenarios) > 0 && x.ValueDate == marginTemplate.ValueDate);
if (sameRuleParameterRecord != null)
{
tradeTypes.AddRange(sameRuleParameterRecord.TradeTypes.Split(','));
}
tradeTypes.ForEach(x =>
{
if (marginTemplate.TradeTypes.Contains(x))
{
throw new Exception("默认规则同一天不能有重复的适用结构:" + x);
}
});
}
else
{
var marginTemplateDefault = yldb.margin_template_v2.Where(x => x.id != marginTemplate.id && x.IsDefault && x.IsValid && !x.IsForClient && (x.BuySellType & marginTemplate.BuySellType) > 0 && (x.MarginScenarios & marginTemplate.MarginScenarios) > 0 && x.ValueDate == marginTemplate.ValueDate);
var existTradeTypes = marginTemplateDefault.Select(x => x.TradeTypes).ToList();
var tradeTypes = new List<string>();
existTradeTypes.ForEach(x => tradeTypes.AddRange(x.Split(',')));
tradeTypes.ForEach(x =>
{
if (marginTemplate.TradeTypes.Contains(x))
{
throw new Exception("默认规则不能有相同的适用结构:" + x);
}
});
}
}
//区间追保结构 + 按资产类型分类时,期限档仅允许"允许分期限档的资产类型"(利率债)或"允许分档的 ETF 子类"
//(可转债 ETF/科创债 ETF,行 UnderlyingType=基金 + EtfKind=子类,不加枚举位)配置,防止非分档类型误配期限档;
//该校验按行生效,与明细行数无关(单行明细同样拦截);
//按严格掩码判定:行标的类型位必须全部落在可分档类型内(混合标志位如 利率债|信用债 配期限档同样拦截,与取数侧整行期限档过滤语义一致);
//UnderlyingType 为空的通配行允许配期限档(取数侧期限档过滤在前、通配匹配在后,语义自洽)
if (marginTemplate.RuleType == (int)MarginRuleTypeEnum.区间追保结构
&& marginTemplate.UnderlyingSeperateType == (int)UnderlyingSeperateTypeEnum.CustomInstrumentType)
{
var enabledMask = ConsMarginTerm.TermTierEnabledUnderlyingTypes.Aggregate(UnderlyingTypeEnum.None, (a, t) => a | t);
var tierEnabledEtfKinds = ConsMarginTerm.TermTierEnabledEtfKinds;
foreach (var detail in marginTemplate.Details)
{
var etfKind = detail.SpanConfig?.EtfKind;
//ETF 子类行:仅允许纯基金行(配置页子类选择器也只在纯基金区块出现)
if (!string.IsNullOrEmpty(etfKind) && detail.UnderlyingType != UnderlyingTypeEnum.Fund)
{
throw new Exception("配置了 ETF 子类(" + etfKind + ")的参数组资产类型必须为 基金及基金专户");
}
var isTierEnabledEtfKind = tierEnabledEtfKinds.Contains(etfKind ?? "");
if (!string.IsNullOrEmpty(detail.SpanConfig?.BondTerm)
&& (detail.UnderlyingType & ~enabledMask) != UnderlyingTypeEnum.None
&& !isTierEnabledEtfKind)
{
throw new Exception("标的类型不允许配置期限档:" + UnderlyingTypeUtil.GetDesc(detail.UnderlyingType));
}
//分档 ETF 子类必须配期限档(区块固定4档),其余子类行禁配期限档
if (!string.IsNullOrEmpty(etfKind))
{
if (isTierEnabledEtfKind && string.IsNullOrEmpty(detail.SpanConfig?.BondTerm))
{
throw new Exception("ETF 子类 " + etfKind + " 为分期限档类型,参数行必须配置期限档");
}
if (!isTierEnabledEtfKind && !string.IsNullOrEmpty(detail.SpanConfig?.BondTerm))
{
throw new Exception("ETF 子类 " + etfKind + " 不分期限档,参数行不能配置期限档");
}
}
}
}
//BUG-13:期限档值须为合法四档(页面为固定区块正常到不了这里,接口直传非法档值会成取数侧永远匹配不到的死配置)
if (marginTemplate.RuleType == (int)MarginRuleTypeEnum.区间追保结构)
{
foreach (var detail in marginTemplate.Details)
{
var bondTerm = detail.SpanConfig?.BondTerm;
if (!string.IsNullOrEmpty(bondTerm) && !ConsMarginTerm.IsValidTerm(bondTerm))
{
throw new Exception("非法的利率债期限档:" + bondTerm + "(允许值:" + string.Join(" / ", ConsMarginTerm.AllowedTerms) + "");
}
}
}
//区间追保结构:客户原型全量手工录入的预警线/平仓线与多空各4层追保区间校验。
//预警线/平仓线/两层区间全部为空视为未配置(兼容存量 x/y 过渡),任一值存在即按规则校验:
//数值非负;同层上下边界都有时上边界>下边界;单层部分填写报错提示完整填写
//(第1层边界特殊:多头第1层只需下边界Lower、空头第1层只需上边界Upper);
//多头各层下边界逐层严格递减、空头各层上边界逐层严格递增(填了才比)。
if (marginTemplate.RuleType == (int)MarginRuleTypeEnum.区间追保结构)
{
for (var i = 0; i < marginTemplate.Details.Count; i++)
{
var cfg = marginTemplate.Details[i].SpanConfig;
if (cfg == null)
{
continue;
}
var longSpans = cfg.LongSpans ?? new List<SpanTierConfig>();
var shortSpans = cfg.ShortSpans ?? new List<SpanTierConfig>();
var hasAnyValue = cfg.WarnLine.HasValue || cfg.CloseLine.HasValue
|| longSpans.Any(t => t != null && (t.Lower.HasValue || t.Upper.HasValue || t.AmountRate.HasValue))
|| shortSpans.Any(t => t != null && (t.Lower.HasValue || t.Upper.HasValue || t.AmountRate.HasValue));
if (!hasAnyValue)
{
continue;
}
var label = "参数组" + (i + 1);
//区块化结构下利率债区块占连续4行(固定4档),报错带上期限档便于定位
if (!string.IsNullOrEmpty(cfg.BondTerm))
{
label += "(利率债期限档 " + cfg.BondTerm + "";
}
if (cfg.WarnLine < 0 || cfg.CloseLine < 0)
{
throw new Exception(label + ":预警线/平仓线不能为负数");
}
ValidateSpanTiers(longSpans, true, label);
ValidateSpanTiers(shortSpans, false, label);
}
}
if (marginTemplate.Details.Count() > 1)
{
if (marginTemplate.RuleType == (int)MarginRuleTypeEnum.区间追保结构)
{
//区间追保结构:按 (利率债期限档, ETF细分) 元组分组校验(EtfKind 为预留扩展键,本期无 UI 写入,等价于仅期限档分组),
//同一分组内标的类型不允许重复,不同分组允许相同标的类型;
//通配行(空/全部,UnderlyingType=None/All)两两之间位与恒为 0 检不出,须单独拦截(BUG-09)——
//否则取数侧通配兜底 matched.First() 命中不确定
foreach (var termGroup in marginTemplate.Details.GroupBy(x => (x.SpanConfig?.BondTerm ?? "", x.SpanConfig?.EtfKind ?? "")))
{
var termUnderlyingType = UnderlyingTypeEnum.None;
var wildcardSeen = false;
foreach (var detail in termGroup)
{
var isWildcard = detail.UnderlyingType == UnderlyingTypeEnum.None || detail.UnderlyingType == UnderlyingTypeEnum.All;
if (isWildcard && wildcardSeen)
{
if (marginTemplate.UnderlyingSeperateType == (int)UnderlyingSeperateTypeEnum.None)
{
throw new Exception("同一利率债期限档下存在重复的参数组");
}
throw new Exception("同一分组下存在重复的兜底参数组(标的类型为空或全部)");
}
if (isWildcard)
{
wildcardSeen = true;
}
if ((detail.UnderlyingType & termUnderlyingType) > 0)
{
if (marginTemplate.UnderlyingSeperateType == (int)UnderlyingSeperateTypeEnum.None)
{
throw new Exception("同一利率债期限档下存在重复的参数组");
}
throw new Exception("存在重复的标的类型:" + UnderlyingTypeUtil.GetDesc(detail.UnderlyingType & termUnderlyingType));
}
termUnderlyingType |= detail.UnderlyingType;
}
}
}
else
{
var underlyingType = UnderlyingTypeEnum.None;
foreach (var detail in marginTemplate.Details)
{
if (detail.UnderlyingType == UnderlyingTypeEnum.None)
{
throw new Exception("标的类型不能为空");
}
if ((detail.UnderlyingType & underlyingType) > 0)
{
throw new Exception("存在重复的标的类型:" + UnderlyingTypeUtil.GetDesc(detail.UnderlyingType & underlyingType));
}
underlyingType |= detail.UnderlyingType;
}
}
}
if (PS.Config.Company == CompanyEnum.广发商贸)
{
if (marginTemplate.Details.Count() > 0)
{
if (marginTemplate.Details[0].SpanConfig.InitialMarginFactor < 0 || marginTemplate.Details[0].SpanConfig.CoefficientFactor < 0)
{
throw new Exception("只能填入大于等于0的数字");
}
}
}
var isAddNew = marginTemplate.id == 0;
if (isAddNew)
{
marginTemplate.OptDate = DateTime.Now;
marginTemplate.OptId = CurUser.UserId;
marginTemplate.OptName = CurUser.UserName;
yldb.margin_template_v2.Add(marginTemplate);
}
else
{
var r = yldb.margin_template_v2.Find(marginTemplate.id);
r.BuySellType = marginTemplate.BuySellType;
r.MarginScenarios = marginTemplate.MarginScenarios;
r.UnderlyingSeperateType = marginTemplate.UnderlyingSeperateType;
r.UnderlyingSeperateComments = marginTemplate.UnderlyingSeperateComments;
r.IsValid = marginTemplate.IsValid;
r.ValueDate = marginTemplate.ValueDate;
r.MarginType = marginTemplate.MarginType;
r.Name = marginTemplate.Name;
r.IsDefault = marginTemplate.IsDefault;
r.IsForClient = marginTemplate.IsForClient;
r.Comments = marginTemplate.Comments;
r.RuleType = marginTemplate.RuleType;
r.TradeTypes = marginTemplate.TradeTypes;
r.OptDate = DateTime.Now;
r.OptId = CurUser.UserId;
r.OptName = CurUser.UserName;
}
var detailIds = marginTemplate.Details.Select(x => x.id).ToArray();
var details = yldb.margin_template_detail.Where(x => !detailIds.Contains(x.id) && x.MarginTemplateId == marginTemplate.id);
yldb.margin_template_detail.RemoveRange(details);
yldb.SaveChanges();
//BUG-14:明细生效日期回写——前端新增行只带占位日期(2020-01-01 前后),此前不回写使新行(含模板拷贝)
//落库 0001-01-01,被取数侧 Max(ValueDate) 分组静默丢弃;占位日期对齐本次提交行的最新生效日期,无有效行时用模板生效日期
var placeholderDate = new DateTime(2020, 1, 1);
var effectiveValueDate = marginTemplate.Details
.Where(d => d.ValueDate > placeholderDate)
.Select(d => d.ValueDate)
.DefaultIfEmpty(marginTemplate.ValueDate > placeholderDate ? marginTemplate.ValueDate : placeholderDate)
.Max();
marginTemplate.Details.ForEach(x =>
{
var detail = yldb.margin_template_detail.Find(x.id);
if (detail == null)
{
detail = new margin_template_detail();
yldb.margin_template_detail.Add(detail);
}
detail.ValueDate = x.ValueDate > placeholderDate ? x.ValueDate : effectiveValueDate;
detail.MarginTemplateId = marginTemplate.id;
detail.GroupRatio = x.GroupRatio;
detail.MarginRatio1 = x.MarginRatio1;
detail.MarginRatio2 = x.MarginRatio2;
detail.MarginRatio3 = x.MarginRatio3;
detail.MarginRatio4 = x.MarginRatio4;
detail.IsIntrinsicValue = x.IsIntrinsicValue;
detail.PriceLimitType = x.PriceLimitType;
detail.UsePositionStockEqvNotional = x.UsePositionStockEqvNotional;
detail.PositionUnderlyingAmount = x.PositionUnderlyingAmount;
detail.RedeemPriceLimit = x.RedeemPriceLimit;
detail.RedeemPriceMax = x.RedeemPriceMax;
detail.IsUseStrike = x.IsUseStrike;
detail.IsNeedCompare = x.IsNeedCompare;
detail.IsUsePriceLimit = x.IsUsePriceLimit;
detail.SingleStockEqvNotional = x.SingleStockEqvNotional;
detail.StockEqvNotional = x.StockEqvNotional;
detail.UnderlyingType = x.UnderlyingType;
detail.ComparedInitialMarginRate = x.ComparedInitialMarginRate;
detail.OptDate = DateTime.Now;
detail.OptId = CurUser.UserId;
detail.OptName = CurUser.UserName;
detail.SpanConfigJson = JsonHelper.Serialize(x.SpanConfig);
yldb.SaveChanges();
});
return JsonSuccess("更新成功");
}
catch (Exception ex)
{
return JsonError(ex.Message);
}
}
/// <summary>
/// 规则15 区间追保结构单方向(多头/空头)4层追保区间校验,报错文案风格与"存在重复的标的类型:xxx"一致。
/// isLong=true 多头:第1层只需下边界 Lower(上不封顶),各层 Lower 逐层严格递减;
/// isLong=false 空头:第1层只需上边界 Upper(下不设限),各层 Upper 逐层严格递增。
/// </summary>
private static void ValidateSpanTiers(List<SpanTierConfig> tiers, bool isLong, string label)
{
var direction = isLong ? "多头方向" : "空头方向";
double? prevBoundary = null;
for (var n = 0; n < tiers.Count; n++)
{
var tier = tiers[n];
if (tier == null)
{
continue;
}
var tierLabel = label + "" + direction + "第" + (n + 1) + "层";
if (tier.Lower < 0 || tier.Upper < 0 || tier.AmountRate < 0)
{
throw new Exception(tierLabel + "追保区间不能为负数");
}
var hasAny = tier.Lower.HasValue || tier.Upper.HasValue || tier.AmountRate.HasValue;
if (!hasAny)
{
continue;
}
if (tier.Lower.HasValue && tier.Upper.HasValue && tier.Upper <= tier.Lower)
{
throw new Exception(tierLabel + "追保区间上边界必须大于下边界");
}
//第1层边界特殊:多头只需 Lower、空头只需 Upper;其余层 Lower/Upper/AmountRate 需完整填写
if (n == 0)
{
if ((isLong && !tier.Lower.HasValue) || (!isLong && !tier.Upper.HasValue) || !tier.AmountRate.HasValue)
{
throw new Exception(tierLabel + "请完整填写追保价格区间与追保金额");
}
}
else if (!tier.Lower.HasValue || !tier.Upper.HasValue || !tier.AmountRate.HasValue)
{
throw new Exception(tierLabel + "请完整填写追保价格区间与追保金额");
}
//逐层单调性:多头 Lower 逐层严格递减、空头 Upper 逐层严格递增(填了才比)
var boundary = isLong ? tier.Lower : tier.Upper;
if (boundary.HasValue)
{
if (prevBoundary.HasValue && (isLong ? boundary >= prevBoundary : boundary <= prevBoundary))
{
throw new Exception(tierLabel + (isLong ? "追保区间下边界须小于上一层的下边界" : "追保区间上边界须大于上一层的上边界"));
}
prevBoundary = boundary;
}
}
}
[HttpPost]
public JsonResult deleteEditmargin_template_v2(string enid)
{
var id = DataProtectHelper.DecryptInt(enid);
var r = yldb.margin_template_v2.Find(id);
if (r == null)
{
return JsonError("删除失败,找不到该预付金规则");
}
yldb.margin_template_v2.Remove(r);
var details = yldb.margin_template_detail.Where(x => x.MarginTemplateId == r.id);
if (details.Any())
{
yldb.margin_template_detail.RemoveRange(details);
}
yldb.SaveChanges();
return JsonSuccess("删除成功");
}
public static List<SelectListItem> GetAllRuleType()
{
var ruleTypeList = new List<SelectListItem>();
if (PS.Config.Is厦门象屿)
{
ruleTypeList.Add(new SelectListItem()
{
Text = MarginRuleTypeEnum.无预付金.ToString(),
Value = ((int)MarginRuleTypeEnum.无预付金).ToString()
});
ruleTypeList.Add(new SelectListItem()
{
Text = MarginRuleTypeEnum.交易所基本规则.ToString(),
Value = ((int)MarginRuleTypeEnum.交易所基本规则).ToString()
});
}
else
{
//预付金模板V2迁移:本部署(TRS)预付金规则只开放 无预付金 和 区间追保结构 两种(2026-08 按业务要求)。
//原"其他公司显示完整规则列表"的代码以块注释形式保留在下方,如需恢复取消注释即可。
ruleTypeList.Add(new SelectListItem()
{
Text = MarginRuleTypeEnum.无预付金.ToString(),
Value = ((int)MarginRuleTypeEnum.无预付金).ToString()
});
ruleTypeList.Add(new SelectListItem()
{
Text = MarginRuleTypeEnum.区间追保结构.ToString(),
Value = ((int)MarginRuleTypeEnum.区间追保结构).ToString()
});
/* 原完整规则列表(保留备查):
ruleTypeList.AddRange(new List<SelectListItem>(){
new SelectListItem()
{
Text = MarginRuleTypeEnum.无预付金.ToString(),
Value = ((int)MarginRuleTypeEnum.无预付金).ToString()
},
new SelectListItem()
{
Text = MarginRuleTypeEnum.按固定利率.ToString(),
Value = ((int)MarginRuleTypeEnum.按固定利率).ToString()
},
new SelectListItem()
{
Text = MarginRuleTypeEnum.按浮动盈亏.ToString(),
Value = ((int)MarginRuleTypeEnum.按浮动盈亏).ToString()
},
new SelectListItem()
{
Text = MarginRuleTypeEnum.类香草预付金规则.ToString(),
Value = ((int)MarginRuleTypeEnum.类香草预付金规则).ToString()
},
new SelectListItem()
{
Text = MarginRuleTypeEnum.自动赎回买入预付金规则.ToString(),
Value = ((int)MarginRuleTypeEnum.自动赎回买入预付金规则).ToString()
},
new SelectListItem()
{
Text = MarginRuleTypeEnum.触发条件预付金规则1.ToString(),
Value = ((int)MarginRuleTypeEnum.触发条件预付金规则1).ToString()
},
new SelectListItem()
{
Text = MarginRuleTypeEnum.触发条件预付金规则2.ToString(),
Value = ((int)MarginRuleTypeEnum.触发条件预付金规则2).ToString()
},
new SelectListItem()
{
Text = MarginRuleTypeEnum.保底预付金规则.ToString(),
Value = ((int)MarginRuleTypeEnum.保底预付金规则).ToString()
},
new SelectListItem()
{
Text = MarginRuleTypeEnum.含赔付预付金计算规则.ToString(),
Value = ((int)MarginRuleTypeEnum.含赔付预付金计算规则).ToString()
},
new SelectListItem()
{
Text = MarginRuleTypeEnum.触发条件预付金规则3.ToString(),
Value = ((int)MarginRuleTypeEnum.触发条件预付金规则3).ToString()
},
new SelectListItem()
{
Text = MarginRuleTypeEnum.标准SPAN.ToString(),
Value = ((int)MarginRuleTypeEnum.标准SPAN).ToString()
},
new SelectListItem()
{
Text = MarginRuleTypeEnum.买入自动赎回规则1.ToString(),
Value = ((int)MarginRuleTypeEnum.买入自动赎回规则1).ToString()
},
new SelectListItem()
{
Text = MarginRuleTypeEnum.卖出自动赎回规则1.ToString(),
Value = ((int)MarginRuleTypeEnum.卖出自动赎回规则1).ToString()
}
});
*/
}
if (PS.Config.Company == CompanyEnum.宏源)
{
ruleTypeList.Add(new SelectListItem()
{
Text = MarginRuleTypeEnum.单独计算规则.ToString(),
Value = ((int)MarginRuleTypeEnum.单独计算规则).ToString()
});
}
return ruleTypeList;
}
}
}