Merge remote-tracking branch 'origin/glms/feature/1.4.2' into glms/feature/1.4.2
This commit is contained in:
@@ -10,33 +10,15 @@ namespace YLErp.DBModels
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 允许配置期限档(SpanConfig.BondTerm)的标的资产类型标志位。
|
/// 允许配置期限档(SpanConfig.BondTerm)的标的资产类型标志位。
|
||||||
/// 区间追保结构"按资产类型分类"时,仅这些类型允许设置非空期限档;
|
/// 区间追保结构"按资产类型分类"时,仅这些类型允许设置非空期限档;
|
||||||
/// 本期仅含 利率债(TBonds=1<<4=16);ETF 子类分档能力见 TermTierEnabledEtfKinds。
|
/// 仅含 利率债(TBonds=1<<4=16)。
|
||||||
|
/// ETF 不分期限档(2026-08-27 业务裁定:ETF 没有期限概念,
|
||||||
|
/// 此前的 可转债 ETF/科创债 ETF 分档白名单 TermTierEnabledEtfKinds 已移除,如需恢复查 git 历史)。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly UnderlyingTypeEnum[] TermTierEnabledUnderlyingTypes =
|
public static readonly UnderlyingTypeEnum[] TermTierEnabledUnderlyingTypes =
|
||||||
{
|
{
|
||||||
UnderlyingTypeEnum.TBonds
|
UnderlyingTypeEnum.TBonds
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 允许配置期限档的 ETF 子类白名单(来自数据字典"ETF 子类")。
|
|
||||||
/// 选择这些子类的 ETF 区块按固定4档展开(同利率债);其余子类/不区分的 ETF 区块单套参数、不分档。
|
|
||||||
/// 取值与 underlying_manager.EtfSubType 字典项一致,由标的维护页维护。
|
|
||||||
/// 注意:分档 ETF 子类行的 UnderlyingType 仍为 基金(32768),不走 TermTierEnabledUnderlyingTypes 位掩码(§1.2 决策:不再加枚举位)。
|
|
||||||
/// </summary>
|
|
||||||
public static readonly List<string> TermTierEnabledEtfKinds = new List<string>
|
|
||||||
{
|
|
||||||
"可转债 ETF",
|
|
||||||
"科创债 ETF"
|
|
||||||
};
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 判断 EtfKind 是否允许分档(在 TermTierEnabledEtfKinds 白名单内)。
|
|
||||||
/// </summary>
|
|
||||||
public static bool IsTermTierEnabledEtfKind(string etfKind)
|
|
||||||
{
|
|
||||||
return !string.IsNullOrEmpty(etfKind) && TermTierEnabledEtfKinds.Contains(etfKind);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 5年以下(同时也是兜底默认期限)
|
/// 5年以下(同时也是兜底默认期限)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -0,0 +1,144 @@
|
|||||||
|
using YLErp.BLL;
|
||||||
|
using YLErp.DBModels;
|
||||||
|
using YLErp.Enums;
|
||||||
|
using YLErp.Modules.MarginModule;
|
||||||
|
|
||||||
|
namespace YLErp.Modules.CalcModules
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// GetRateByTemplate 资产类型先行匹配回归(连 dev 库,2026-08-27 顺序裁定:先品种后期限):
|
||||||
|
/// 期限档仅利率债允许配置,品种匹配在期限之前——防止非利率债标的被利率债期限档行截胡
|
||||||
|
/// (交易2567 实证:信用债标的按 "<5y" 精确匹配到利率债行,信用债行 BondTerm 空永远不参与)。
|
||||||
|
/// 标的代码用库里不存在的代码(GetApplicableMarginTerm 无标的兜底返回 <5y),不依赖真实标的行情数据。
|
||||||
|
/// 测试数据全部带 "ZZZ-品种先行测试-" 名称前缀,TestInitialize/TestCleanup 双向清理。
|
||||||
|
/// </summary>
|
||||||
|
[TestClass]
|
||||||
|
public class MarginTemplateV2InstrumentFirstMatchTest
|
||||||
|
{
|
||||||
|
private const string Marker = "ZZZ-品种先行测试-";
|
||||||
|
private DateTime EffectiveDate = new DateTime(2000, 1, 1);
|
||||||
|
|
||||||
|
private YLContext db;
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Init()
|
||||||
|
{
|
||||||
|
db = new YLContext();
|
||||||
|
Cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCleanup]
|
||||||
|
public void CleanupFixture()
|
||||||
|
{
|
||||||
|
Cleanup();
|
||||||
|
db.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cleanup()
|
||||||
|
{
|
||||||
|
var templateIds = db.margin_template_v2.Where(x => x.Name.StartsWith(Marker)).Select(x => x.id).ToList();
|
||||||
|
if (templateIds.Count > 0)
|
||||||
|
{
|
||||||
|
db.margin_template_detail.RemoveRange(db.margin_template_detail.Where(x => templateIds.Contains(x.MarginTemplateId)));
|
||||||
|
db.margin_template_v2.RemoveRange(db.margin_template_v2.Where(x => templateIds.Contains(x.id)));
|
||||||
|
db.SaveChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private margin_template_v2 AddTieredTemplate()
|
||||||
|
{
|
||||||
|
var t = new margin_template_v2
|
||||||
|
{
|
||||||
|
Name = Marker + "分档",
|
||||||
|
IsDefault = false,
|
||||||
|
IsForClient = false,
|
||||||
|
IsValid = true,
|
||||||
|
TradeTypes = "收益互换",
|
||||||
|
RuleType = (int)MarginRuleTypeEnum.区间追保结构,
|
||||||
|
UnderlyingSeperateType = (int)UnderlyingSeperateTypeEnum.CustomInstrumentType,
|
||||||
|
ValueDate = EffectiveDate
|
||||||
|
};
|
||||||
|
db.margin_template_v2.Add(t);
|
||||||
|
db.SaveChanges();
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddDetail(int templateId, UnderlyingTypeEnum underlyingType, string bondTermJson, double initRate, double maintainRate)
|
||||||
|
{
|
||||||
|
db.margin_template_detail.Add(new margin_template_detail
|
||||||
|
{
|
||||||
|
MarginTemplateId = templateId,
|
||||||
|
ValueDate = EffectiveDate,
|
||||||
|
UnderlyingType = underlyingType,
|
||||||
|
SpanConfigJson = bondTermJson,
|
||||||
|
MarginRatio1 = initRate,
|
||||||
|
MarginRatio2 = maintainRate
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 信用债标的不被利率债期限档行截胡:term 恒为 "<5y"(标的不存在兜底),
|
||||||
|
/// 旧序会精确命中利率债 <5y 行;新序品种先行应命中信用债行(BondTerm 空)。
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TI_001_信用债标的_命中信用债行_不被利率债期限档截胡()
|
||||||
|
{
|
||||||
|
var tpl = AddTieredTemplate();
|
||||||
|
AddDetail(tpl.id, UnderlyingTypeEnum.TBonds, "{\"BondTerm\":\"<5y\"}", 0.11, 0.12);
|
||||||
|
AddDetail(tpl.id, UnderlyingTypeEnum.CreditBonds, null, 0.05, 0.06);
|
||||||
|
db.SaveChanges();
|
||||||
|
|
||||||
|
var rate = MarginTemplateV2RateHelper.GetRateByTemplate(tpl, "ZZZ-NOT-EXIST-CD.IB", "CreditBonds", DateTime.Today, db);
|
||||||
|
Assert.IsNotNull(rate, "品种先行后信用债行(BondTerm 空)应经期限兜底命中");
|
||||||
|
Assert.AreEqual(0.05m, rate.InitRate.Value, "应取信用债行的初始预付金率,而非利率债 <5y 行的 0.11");
|
||||||
|
Assert.AreEqual(0.06m, rate.MaintainRate.Value, "应取信用债行的维持预付金率,而非利率债 <5y 行的 0.12");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 利率债标的行为不变:品种命中利率债行后,期限精确档 "<5y" 命中对应期限行(压过 5y-10y 行)。
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TI_002_利率债标的_品种内期限精确档仍生效()
|
||||||
|
{
|
||||||
|
var tpl = AddTieredTemplate();
|
||||||
|
AddDetail(tpl.id, UnderlyingTypeEnum.TBonds, "{\"BondTerm\":\"<5y\"}", 0.11, 0.12);
|
||||||
|
AddDetail(tpl.id, UnderlyingTypeEnum.TBonds, "{\"BondTerm\":\"5y-10y\"}", 0.13, 0.14);
|
||||||
|
db.SaveChanges();
|
||||||
|
|
||||||
|
var rate = MarginTemplateV2RateHelper.GetRateByTemplate(tpl, "ZZZ-NOT-EXIST-TB.IB", "TBonds", DateTime.Today, db);
|
||||||
|
Assert.IsNotNull(rate);
|
||||||
|
Assert.AreEqual(0.11m, rate.InitRate.Value, "期限兜底 <5y 时应精确命中 <5y 档行");
|
||||||
|
Assert.AreEqual(0.12m, rate.MaintainRate.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 模板未配标的品种时的既有兜底不变:品种行与通配行均无 → 不缩小行集,回落期限匹配(与旧序一致)。
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TI_003_模板未配品种_回落期限匹配_行为不变()
|
||||||
|
{
|
||||||
|
var tpl = AddTieredTemplate();
|
||||||
|
AddDetail(tpl.id, UnderlyingTypeEnum.TBonds, "{\"BondTerm\":\"<5y\"}", 0.11, 0.12);
|
||||||
|
db.SaveChanges();
|
||||||
|
|
||||||
|
var rate = MarginTemplateV2RateHelper.GetRateByTemplate(tpl, "ZZZ-NOT-EXIST-CF.IB", "CommodityFutures", DateTime.Today, db);
|
||||||
|
Assert.IsNotNull(rate, "品种落空应回落到期限匹配(旧行为兜底),不应返回 null");
|
||||||
|
Assert.AreEqual(0.11m, rate.InitRate.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 品种行与期限行均无法匹配时返回 null:非利率债标的不再"借用"利率债期限档行,
|
||||||
|
/// 由调用方按无预付金要求兜底(引擎不产出 trade_span)。
|
||||||
|
/// </summary>
|
||||||
|
[TestMethod]
|
||||||
|
public void TI_004_品种与期限均无匹配行_返回null()
|
||||||
|
{
|
||||||
|
var tpl = AddTieredTemplate();
|
||||||
|
AddDetail(tpl.id, UnderlyingTypeEnum.TBonds, "{\"BondTerm\":\"5y-10y\"}", 0.13, 0.14);
|
||||||
|
db.SaveChanges();
|
||||||
|
|
||||||
|
var rate = MarginTemplateV2RateHelper.GetRateByTemplate(tpl, "ZZZ-NOT-EXIST-CD.IB", "CreditBonds", DateTime.Today, db);
|
||||||
|
Assert.IsNull(rate, "信用债标的不应命中利率债 5y-10y 期限行");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -171,6 +171,7 @@ namespace YLErp
|
|||||||
"yladmin" => _configuration.GetConnectionString("yladmin"),
|
"yladmin" => _configuration.GetConnectionString("yladmin"),
|
||||||
"ylclient" => _configuration.GetConnectionString("ylclient"),
|
"ylclient" => _configuration.GetConnectionString("ylclient"),
|
||||||
"bondoms" => _configuration.GetConnectionString("bondoms"),
|
"bondoms" => _configuration.GetConnectionString("bondoms"),
|
||||||
|
"glms_bigdata" => _configuration.GetConnectionString("glms_bigdata"),
|
||||||
"apex_oracle"=> _configuration.GetConnectionString("apex_oracle"),
|
"apex_oracle"=> _configuration.GetConnectionString("apex_oracle"),
|
||||||
_ => string.Empty,
|
_ => string.Empty,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -129,19 +129,39 @@ namespace YLErp.Modules.MarginModule
|
|||||||
var latestValueDate = detailQuery.Max(x => x.ValueDate);
|
var latestValueDate = detailQuery.Max(x => x.ValueDate);
|
||||||
var details = detailQuery.Where(x => x.ValueDate == latestValueDate).ToList();
|
var details = detailQuery.Where(x => x.ValueDate == latestValueDate).ToList();
|
||||||
|
|
||||||
//4.利率债/分档ETF 期限档匹配:精确档 → "全部"(BondTerm 为空)兜底
|
//4.资产类型先行(2026-08-27 顺序裁定:先品种后期限):按资产类型分档的模板先按标的品种缩小行集——
|
||||||
|
//品种行 → 通配行(None/All)→ 均无则不缩小(回落到与旧序一致的期限匹配,模板未配该品种的既有兜底不变)。
|
||||||
|
//期限档仅利率债允许配置(ConsMarginTerm),品种匹配必须在期限之前:期限精确匹配对任何标的恒有 term
|
||||||
|
//(GetApplicableMarginTerm 兜底 <5y),非利率债标的会被利率债期限档行截胡、本品种行(BondTerm 空)永远不参与
|
||||||
|
//(2026-08-27 交易2567 实证:信用债标的按 "<5y" 命中利率债行多收追保)
|
||||||
|
var candidates = details;
|
||||||
|
if (template.UnderlyingSeperateType == (int)UnderlyingSeperateTypeEnum.CustomInstrumentType
|
||||||
|
&& Enum.TryParse<UnderlyingTypeEnum>(underlyingInstrumentType, out var instrumentFlag))
|
||||||
|
{
|
||||||
|
var byInstrument = details.Where(x => (x.UnderlyingType & instrumentFlag) > 0).ToList();
|
||||||
|
if (!byInstrument.Any())
|
||||||
|
{
|
||||||
|
byInstrument = details.Where(x => x.UnderlyingType == UnderlyingTypeEnum.None || x.UnderlyingType == UnderlyingTypeEnum.All).ToList();
|
||||||
|
}
|
||||||
|
if (byInstrument.Any())
|
||||||
|
{
|
||||||
|
candidates = byInstrument;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//5.期限档匹配(利率债四档):精确档 → "全部"(BondTerm 为空)兜底
|
||||||
var term = UnderlyingHelper.GetApplicableMarginTerm(underlyingCode, valueDate);
|
var term = UnderlyingHelper.GetApplicableMarginTerm(underlyingCode, valueDate);
|
||||||
var matched = details.Where(x => x.SpanConfig != null && x.SpanConfig.BondTerm == term).ToList();
|
var matched = candidates.Where(x => x.SpanConfig != null && x.SpanConfig.BondTerm == term).ToList();
|
||||||
if (!matched.Any())
|
if (!matched.Any())
|
||||||
{
|
{
|
||||||
matched = details.Where(x => x.SpanConfig == null || string.IsNullOrEmpty(x.SpanConfig.BondTerm)).ToList();
|
matched = candidates.Where(x => x.SpanConfig == null || string.IsNullOrEmpty(x.SpanConfig.BondTerm)).ToList();
|
||||||
}
|
}
|
||||||
if (!matched.Any())
|
if (!matched.Any())
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//5.ETF 子类行优先(子类区分度高于期限):标的有 EtfSubType(基金类)时优先取 EtfKind=子类 的行——
|
//6.ETF 子类行优先(子类区分度高于期限):标的有 EtfSubType(基金类)时优先取 EtfKind=子类 的行——
|
||||||
//期限档匹配未命中子类行时再单独尝试"子类 + BondTerm 空"(子类不分档通配);无子类行维持原 matched(基金通配兜底)
|
//期限档匹配未命中子类行时再单独尝试"子类 + BondTerm 空"(子类不分档通配);无子类行维持原 matched(基金通配兜底)
|
||||||
var underlyingCategory = GetUnderlyingCategory(underlyingCode, underlyingInstrumentType);
|
var underlyingCategory = GetUnderlyingCategory(underlyingCode, underlyingInstrumentType);
|
||||||
if (underlyingCategory != null)
|
if (underlyingCategory != null)
|
||||||
@@ -149,24 +169,6 @@ namespace YLErp.Modules.MarginModule
|
|||||||
matched = PreferCategoryRows(matched, details, underlyingCategory);
|
matched = PreferCategoryRows(matched, details, underlyingCategory);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (template.UnderlyingSeperateType == (int)UnderlyingSeperateTypeEnum.CustomInstrumentType
|
|
||||||
&& Enum.TryParse<UnderlyingTypeEnum>(underlyingInstrumentType, out var instrumentFlag))
|
|
||||||
{
|
|
||||||
var byInstrument = matched.Where(x => (x.UnderlyingType & instrumentFlag) > 0).ToList();
|
|
||||||
if (byInstrument.Any())
|
|
||||||
{
|
|
||||||
matched = byInstrument;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var wildcard = matched.Where(x => x.UnderlyingType == UnderlyingTypeEnum.None || x.UnderlyingType == UnderlyingTypeEnum.All).ToList();
|
|
||||||
if (wildcard.Any())
|
|
||||||
{
|
|
||||||
matched = wildcard;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var detail = matched.First();
|
var detail = matched.First();
|
||||||
return new MarginRateResult
|
return new MarginRateResult
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
using Dapper;
|
||||||
|
using MySqlConnector;
|
||||||
|
using YieldChain.Helpers;
|
||||||
|
using YLErp.BLL;
|
||||||
|
|
||||||
|
namespace YLErp.Modules.UnderlyingModule
|
||||||
|
{
|
||||||
|
public enum FundManagerLookupStatus
|
||||||
|
{
|
||||||
|
NotFound,
|
||||||
|
Unique,
|
||||||
|
Multiple,
|
||||||
|
Unavailable
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class FundManagerLookupResult
|
||||||
|
{
|
||||||
|
public FundManagerLookupStatus Status { get; init; }
|
||||||
|
public string InvestAdvisorName { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询上游基金档案中的基金管理人。上游不可用时返回降级结果,不阻断页面编辑。
|
||||||
|
/// </summary>
|
||||||
|
public sealed class FundManagerLookupService
|
||||||
|
{
|
||||||
|
private sealed class FundManagerRow
|
||||||
|
{
|
||||||
|
public string InvestAdvisorCode { get; set; }
|
||||||
|
public string InvestAdvisorName { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private const string LookupSql = @"
|
||||||
|
SELECT
|
||||||
|
ia.investadvisorcode AS InvestAdvisorCode,
|
||||||
|
ia.investadvisorname AS InvestAdvisorName
|
||||||
|
FROM glms_bigdata.mf_fundarchives AS fa
|
||||||
|
INNER JOIN glms_bigdata.mf_investadvisoroutline AS ia
|
||||||
|
ON CONVERT(fa.investadvisorcode USING utf8mb4) COLLATE utf8mb4_unicode_ci =
|
||||||
|
CONVERT(ia.investadvisorcode USING utf8mb4) COLLATE utf8mb4_unicode_ci
|
||||||
|
WHERE CONVERT(fa.secucode USING utf8mb4) COLLATE utf8mb4_unicode_ci =
|
||||||
|
CONVERT(TRIM(SUBSTRING_INDEX(@UnderlyingCode, '.', 1)) USING utf8mb4) COLLATE utf8mb4_unicode_ci";
|
||||||
|
|
||||||
|
public FundManagerLookupResult Lookup(string underlyingCode)
|
||||||
|
{
|
||||||
|
var normalizedCode = NormalizeCode(underlyingCode);
|
||||||
|
if (string.IsNullOrEmpty(normalizedCode))
|
||||||
|
{
|
||||||
|
return new FundManagerLookupResult { Status = FundManagerLookupStatus.NotFound };
|
||||||
|
}
|
||||||
|
|
||||||
|
var connectionString = AppManager.GetConnectionString("glms_bigdata");
|
||||||
|
if (string.IsNullOrWhiteSpace(connectionString))
|
||||||
|
{
|
||||||
|
return new FundManagerLookupResult { Status = FundManagerLookupStatus.Unavailable };
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var connection = new MySqlConnection(connectionString);
|
||||||
|
var matches = connection.Query<FundManagerRow>(LookupSql, new { UnderlyingCode = normalizedCode }, commandTimeout: 10)
|
||||||
|
.Where(row => !string.IsNullOrWhiteSpace(row.InvestAdvisorName))
|
||||||
|
.GroupBy(row => (row.InvestAdvisorCode ?? string.Empty).Trim(), StringComparer.OrdinalIgnoreCase)
|
||||||
|
.Select(group => group.Select(row => row.InvestAdvisorName.Trim()).Distinct(StringComparer.OrdinalIgnoreCase).ToArray())
|
||||||
|
.Where(names => names.Length > 0)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
return matches.Length switch
|
||||||
|
{
|
||||||
|
0 => new FundManagerLookupResult { Status = FundManagerLookupStatus.NotFound },
|
||||||
|
1 when matches[0].Length == 1 => new FundManagerLookupResult { Status = FundManagerLookupStatus.Unique, InvestAdvisorName = matches[0][0] },
|
||||||
|
_ => new FundManagerLookupResult { Status = FundManagerLookupStatus.Multiple }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogFactory.GetLogger<FundManagerLookupService>().Error("查询基金管理人失败,代码:" + normalizedCode, ex);
|
||||||
|
return new FundManagerLookupResult { Status = FundManagerLookupStatus.Unavailable };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string NormalizeCode(string underlyingCode)
|
||||||
|
{
|
||||||
|
var trimmed = underlyingCode?.Trim();
|
||||||
|
if (string.IsNullOrEmpty(trimmed))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var dotIndex = trimmed.IndexOf('.');
|
||||||
|
return (dotIndex < 0 ? trimmed : trimmed.Substring(0, dotIndex)).TrimToNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -85,54 +85,6 @@ namespace YLErp.Web.Controllers
|
|||||||
return View(model);
|
return View(model);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 组合报价
|
|
||||||
/// </summary>
|
|
||||||
[MyAuthorize("报价管理-结构化交易定价")]
|
|
||||||
public ActionResult Structure_DZ()
|
|
||||||
{
|
|
||||||
var otcTrade = new OtcOptionTradeFull()
|
|
||||||
{
|
|
||||||
TraderId = CurUser.UserId,
|
|
||||||
TraderName = CurUser.UserName,
|
|
||||||
BuySell = "卖出",
|
|
||||||
VolType = "交易",
|
|
||||||
TradeType = "香草期权",
|
|
||||||
OptionType = "看涨",
|
|
||||||
ExerciseMode = "European",
|
|
||||||
TradeDate = valuedateBLL.ValueDate,
|
|
||||||
UnderlyingInstrumentType = AppHelper.OtcConfig.StockFirst ? "Stock" : "CommodityFutures",
|
|
||||||
SettlementType = (int)SettlementTypeEnum.ClosePrice,
|
|
||||||
NoRiskRate = valuedateBLL.SystemDate.RiskFreeRate / 100,
|
|
||||||
ParticipationRate = 1,
|
|
||||||
AnnualizeFactor = 1,
|
|
||||||
MarginTemplateName = "系统默认",
|
|
||||||
CouponIncludeStartDate = false,
|
|
||||||
CouponUsePaymentDate = false
|
|
||||||
};
|
|
||||||
|
|
||||||
var model = new Models.PricingModel(CurUser, UserBLL.IsTradeOfCurrentLogin(CurUser.UserId)) { Trade = otcTrade };
|
|
||||||
|
|
||||||
if (model.NumOfSmoothingDaysCfg == "ONE")
|
|
||||||
{
|
|
||||||
model.Trade.NumOfSmoothingDays = 1;
|
|
||||||
}
|
|
||||||
//获取自定义结构信息
|
|
||||||
var structureTypes =
|
|
||||||
new StructureService(CurUser)
|
|
||||||
.QueryStructureMap(StructureRangeEnum.BALCK_TRADE);
|
|
||||||
var structureTypeMap = new Dictionary<string, List<Structure_Details>>() {
|
|
||||||
{ "气囊结构",new List<Structure_Details>() }
|
|
||||||
};
|
|
||||||
foreach (var item in structureTypes)
|
|
||||||
{
|
|
||||||
structureTypeMap[item.Key] = item.Value;
|
|
||||||
}
|
|
||||||
ViewBag.StructureTypeMap = structureTypeMap;
|
|
||||||
|
|
||||||
return View(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 组合报价导入
|
/// 组合报价导入
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -198,11 +150,6 @@ namespace YLErp.Web.Controllers
|
|||||||
ViewBag.ExtendInfoMap[item.Key] = item.Value;
|
ViewBag.ExtendInfoMap[item.Key] = item.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PS.Config.Is润和)
|
|
||||||
{
|
|
||||||
return View(nameof(Structure_DZ), model);
|
|
||||||
}
|
|
||||||
|
|
||||||
return View(nameof(Structure), model);
|
return View(nameof(Structure), model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -304,8 +304,8 @@ namespace YLErp.Web.Controllers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//区间追保结构 + 按资产类型分类时,期限档仅允许"允许分期限档的资产类型"(利率债)或"允许分档的 ETF 子类"
|
//区间追保结构 + 按资产类型分类时,期限档仅允许利率债配置(2026-08-27 裁定:ETF 无期限概念,
|
||||||
//(可转债 ETF/科创债 ETF,行 UnderlyingType=基金 + EtfKind=子类,不加枚举位)配置,防止非分档类型误配期限档;
|
//可转债 ETF/科创债 ETF 的分档白名单已移除,所有 ETF 子类/基金行一律单套参数不分档),防止非分档类型误配期限档;
|
||||||
//该校验按行生效,与明细行数无关(单行明细同样拦截);
|
//该校验按行生效,与明细行数无关(单行明细同样拦截);
|
||||||
//按严格掩码判定:行标的类型位必须全部落在可分档类型内(混合标志位如 利率债|信用债 配期限档同样拦截,与取数侧整行期限档过滤语义一致);
|
//按严格掩码判定:行标的类型位必须全部落在可分档类型内(混合标志位如 利率债|信用债 配期限档同样拦截,与取数侧整行期限档过滤语义一致);
|
||||||
//UnderlyingType 为空的通配行允许配期限档(取数侧期限档过滤在前、通配匹配在后,语义自洽)
|
//UnderlyingType 为空的通配行允许配期限档(取数侧期限档过滤在前、通配匹配在后,语义自洽)
|
||||||
@@ -313,34 +313,24 @@ namespace YLErp.Web.Controllers
|
|||||||
&& marginTemplate.UnderlyingSeperateType == (int)UnderlyingSeperateTypeEnum.CustomInstrumentType)
|
&& marginTemplate.UnderlyingSeperateType == (int)UnderlyingSeperateTypeEnum.CustomInstrumentType)
|
||||||
{
|
{
|
||||||
var enabledMask = ConsMarginTerm.TermTierEnabledUnderlyingTypes.Aggregate(UnderlyingTypeEnum.None, (a, t) => a | t);
|
var enabledMask = ConsMarginTerm.TermTierEnabledUnderlyingTypes.Aggregate(UnderlyingTypeEnum.None, (a, t) => a | t);
|
||||||
var tierEnabledEtfKinds = ConsMarginTerm.TermTierEnabledEtfKinds;
|
|
||||||
foreach (var detail in marginTemplate.Details)
|
foreach (var detail in marginTemplate.Details)
|
||||||
{
|
{
|
||||||
var etfKind = detail.SpanConfig?.EtfKind;
|
var etfKind = detail.SpanConfig?.EtfKind;
|
||||||
|
var bondTerm = detail.SpanConfig?.BondTerm;
|
||||||
//ETF 子类行:仅允许纯基金行(配置页子类选择器也只在纯基金区块出现)
|
//ETF 子类行:仅允许纯基金行(配置页子类选择器也只在纯基金区块出现)
|
||||||
if (!string.IsNullOrEmpty(etfKind) && detail.UnderlyingType != UnderlyingTypeEnum.Fund)
|
if (!string.IsNullOrEmpty(etfKind) && detail.UnderlyingType != UnderlyingTypeEnum.Fund)
|
||||||
{
|
{
|
||||||
throw new Exception("配置了 ETF 子类(" + etfKind + ")的参数组资产类型必须为 基金及基金专户");
|
throw new Exception("配置了 ETF 子类(" + etfKind + ")的参数组资产类型必须为 基金及基金专户");
|
||||||
}
|
}
|
||||||
var isTierEnabledEtfKind = tierEnabledEtfKinds.Contains(etfKind ?? "");
|
//ETF 子类不分期限档(对存量 4 档子类行回存给出精确报错;基金通配行由下面的掩码校验拦截)
|
||||||
if (!string.IsNullOrEmpty(detail.SpanConfig?.BondTerm)
|
if (!string.IsNullOrEmpty(etfKind) && !string.IsNullOrEmpty(bondTerm))
|
||||||
&& (detail.UnderlyingType & ~enabledMask) != UnderlyingTypeEnum.None
|
{
|
||||||
&& !isTierEnabledEtfKind)
|
throw new Exception("ETF 子类 " + etfKind + " 不分期限档,参数行不能配置期限档");
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(bondTerm) && (detail.UnderlyingType & ~enabledMask) != UnderlyingTypeEnum.None)
|
||||||
{
|
{
|
||||||
throw new Exception("标的类型不允许配置期限档:" + UnderlyingTypeUtil.GetDesc(detail.UnderlyingType));
|
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 + " 不分期限档,参数行不能配置期限档");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,8 +389,8 @@ namespace YLErp.Web.Controllers
|
|||||||
{
|
{
|
||||||
if (marginTemplate.RuleType == (int)MarginRuleTypeEnum.区间追保结构)
|
if (marginTemplate.RuleType == (int)MarginRuleTypeEnum.区间追保结构)
|
||||||
{
|
{
|
||||||
//区间追保结构:按 (利率债期限档, ETF细分) 元组分组校验(EtfKind 为预留扩展键,本期无 UI 写入,等价于仅期限档分组),
|
//区间追保结构:按 (利率债期限档, ETF细分) 元组分组校验——期限档仅利率债有值(其余恒空),
|
||||||
//同一分组内标的类型不允许重复,不同分组允许相同标的类型;
|
//EtfKind 为基金行的子类键;同一分组内标的类型不允许重复,不同分组允许相同标的类型;
|
||||||
//通配行(空/全部,UnderlyingType=None/All)两两之间位与恒为 0 检不出,须单独拦截(BUG-09)——
|
//通配行(空/全部,UnderlyingType=None/All)两两之间位与恒为 0 检不出,须单独拦截(BUG-09)——
|
||||||
//否则取数侧通配兜底 matched.First() 命中不确定
|
//否则取数侧通配兜底 matched.First() 命中不确定
|
||||||
foreach (var termGroup in marginTemplate.Details.GroupBy(x => (x.SpanConfig?.BondTerm ?? "", x.SpanConfig?.EtfKind ?? "")))
|
foreach (var termGroup in marginTemplate.Details.GroupBy(x => (x.SpanConfig?.BondTerm ?? "", x.SpanConfig?.EtfKind ?? "")))
|
||||||
|
|||||||
@@ -525,6 +525,25 @@ namespace YLErp.Web.Controllers
|
|||||||
return JsonSuccess("", underlying);
|
return JsonSuccess("", underlying);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询上游基金档案中的基金管理人。查询失败或结果不唯一时返回可降级结果。
|
||||||
|
/// </summary>
|
||||||
|
[HttpGet]
|
||||||
|
public JsonResult GetFundManager(string code, string instrumentType)
|
||||||
|
{
|
||||||
|
if (!string.Equals(instrumentType, ConsGlobal.InstrumentType.Fund, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return JsonSuccess("", new FundManagerLookupResult { Status = FundManagerLookupStatus.NotFound });
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = new FundManagerLookupService().Lookup(code);
|
||||||
|
return JsonSuccess("", new
|
||||||
|
{
|
||||||
|
result.InvestAdvisorName,
|
||||||
|
IsUnique = result.Status == FundManagerLookupStatus.Unique
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 预付金参数
|
/// 预付金参数
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,910 +0,0 @@
|
|||||||
@using Microsoft.AspNetCore.Html
|
|
||||||
@using YLErp.QdpModule.Constants
|
|
||||||
@model PricingModel
|
|
||||||
@{
|
|
||||||
ViewBag.Title = "期权定价";
|
|
||||||
|
|
||||||
if (Model.IsImport)
|
|
||||||
{
|
|
||||||
Layout = "~/Views/Shared/_InfoLayout.cshtml";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Layout = "~/Views/Shared/_MainLayout.cshtml";
|
|
||||||
}
|
|
||||||
var assetunits = JsDataModel.GetAssetUnits(CurUser);
|
|
||||||
var traders = JsDataModel.GetTraders(assetunits);
|
|
||||||
var pageObj = new
|
|
||||||
{
|
|
||||||
assetunits = assetunits,
|
|
||||||
trade = new trade() { Strike = 0 },
|
|
||||||
traders = JsDataModel.GetTraders(assetunits),
|
|
||||||
tradeMarginTemplateItems = new tradeController().GetMarginTemplateItems(),
|
|
||||||
tradeMarginTemplates = new tradeController().GetMarginTemplates(),
|
|
||||||
engineNames = new[] { "abc", "xyz" },
|
|
||||||
structureTypes = ViewBag.StructureTypeMap?.Keys,
|
|
||||||
PropertyMap = ViewBag.StructureTypeMap,
|
|
||||||
IsPVIncludePrincipal = PS.Config.ErpElement.IsPVIncludePrincipal
|
|
||||||
};
|
|
||||||
var pageData = new
|
|
||||||
{
|
|
||||||
showCCR = PS.Config.Company == CompanyEnum.国海,
|
|
||||||
is厦门象屿 = PS.Config.Company == CompanyEnum.厦门象屿,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@section CSS{
|
|
||||||
<link href="~/Style/Css/pricing.structure.css?v=1" rel="stylesheet" />
|
|
||||||
@switch (PS.Config.Company)
|
|
||||||
{
|
|
||||||
case CompanyEnum.光大光子:
|
|
||||||
<link href="~/Style/GDGZ/pricing.structure.css" rel="stylesheet" />
|
|
||||||
break;
|
|
||||||
case CompanyEnum.国泰君安:
|
|
||||||
<link href="~/Style/GTJA/pricing.structure.css" rel="stylesheet" />
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
<style>
|
|
||||||
.pitem-cash:not(.pitem) {
|
|
||||||
background: #f0f8ff
|
|
||||||
}
|
|
||||||
|
|
||||||
.customPanel {
|
|
||||||
background: #CDE0E6;
|
|
||||||
height: 100%;
|
|
||||||
display: table;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autocomplete-suggestions {
|
|
||||||
width: auto !important;
|
|
||||||
min-width: 11%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.pricing-item {
|
|
||||||
transform: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.empty {
|
|
||||||
border-top: none !important;
|
|
||||||
background: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bottomborder {
|
|
||||||
border-bottom: 1px solid #ddd !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.topborder {
|
|
||||||
border-top: 1px solid #ddd !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
}
|
|
||||||
@section JS{
|
|
||||||
<script src="~/Statics/libs/_utils/dragscroll.js?v=@(HtmlUtil.JsVersion)"></script>
|
|
||||||
<script src="~/Statics/libs/_utils/FileSaver.js?v=@(HtmlUtil.JsVersion)"></script>
|
|
||||||
<script src="~/Statics/libs/_utils/dom-to-image.min.js?v=@(HtmlUtil.JsVersion)"></script>
|
|
||||||
<script src="~/Statics/libs/sortable/Sortable.min.js"></script>
|
|
||||||
<script src="~/front/calendar?v=@(HtmlUtil.JsVersion)"></script>
|
|
||||||
<script src="~/Scripts/app/tradeHelper.js?v=@HtmlUtil.JsVersion"></script>
|
|
||||||
<script src="~/Scripts/app/trade/percentColumnText.js?v=@HtmlUtil.JsVersion"></script>
|
|
||||||
<script src="@HtmlUtil.BasicDataJs("品种", "客户")"></script>
|
|
||||||
<script>
|
|
||||||
const pageObj = @Json.Serialize(pageObj);
|
|
||||||
const pageData = @Json.Serialize(pageData);
|
|
||||||
const pageVue = @Json.Serialize(Model);
|
|
||||||
const optionTradeTypes = Object.freeze([{ value: "香草期权", pinyin: 'XCQQ' },
|
|
||||||
{ value: "障碍期权", pinyin: 'ZAQQ' }, { value: "二元期权", pinyin: 'EYQQ' },
|
|
||||||
{ value: "亚式期权", pinyin: 'YSQQ' }, { value: "凤凰期权", pinyin: 'FHQQ' },
|
|
||||||
{ value: "雪球期权", pinyin: 'XQQQ' }, { value: "结构化产品", pinyin: 'JGHCP' },
|
|
||||||
]);
|
|
||||||
pageVue.GetTotalMargin = function (trades, structureType) {
|
|
||||||
return _.reduce(trades, (acc, cur) => acc += parseFloat(cur.InitialMargin) || 0, 0);
|
|
||||||
};
|
|
||||||
pageVue.GetTotalTradePrice = function (trades) {
|
|
||||||
return _.reduce(trades, (acc, cur) => acc += parseFloat(cur.TradePrice) || 0, 0);
|
|
||||||
};
|
|
||||||
pageVue.GetTotalDay1Pnl = function (trades) {
|
|
||||||
return _.reduce(trades, (acc, cur) => acc += parseFloat(cur.Day1Pnl) || 0, 0);
|
|
||||||
};
|
|
||||||
pageVue.CalcVersion = "@(Context.Request.Query["version"])";
|
|
||||||
ylotc.trade = pageObj.trade;
|
|
||||||
ylotc.traders = pageObj.traders;
|
|
||||||
ylotc.assetunits = pageObj.assetunits;
|
|
||||||
ylotc.tradeMarginTemplateItems = pageObj.tradeMarginTemplateItems;
|
|
||||||
ylotc.tradeMarginTemplates = pageObj.tradeMarginTemplates;
|
|
||||||
ylotc.engineNames = pageObj.engineNames;
|
|
||||||
ylotc.options = pageObj.options;
|
|
||||||
ylotc.structureTypes = pageObj.structureTypes;
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
@if (PS.Config.Company == CompanyEnum.伴兴)
|
|
||||||
{
|
|
||||||
<script>
|
|
||||||
pageVue.GetTotalMargin = function (trades, structureType) {
|
|
||||||
if (trades.length === 1) return parseFloat(trades[0].InitialMargin) || 0;
|
|
||||||
if (!structureType || structureType === "结构化交易") {
|
|
||||||
return _.reduce(trades, (acc, cur) => acc += parseFloat(cur.InitialMargin) || 0, 0);
|
|
||||||
}
|
|
||||||
if (structureType.indexOf("跨式") >= 0) {
|
|
||||||
return _.max(_.map(trades, x => Math.abs(x.InitialMargin)));
|
|
||||||
}
|
|
||||||
return _.reduce(trades, (acc, cur) => acc += cur.BuySell === '卖出' ? 0 : parseFloat(cur.InitialMargin) || 0, 0);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
}
|
|
||||||
else if (PS.Config.Company == CompanyEnum.茂川资本)
|
|
||||||
{
|
|
||||||
<script>
|
|
||||||
pageVue.GetTotalMargin = function (trades, structureType) {
|
|
||||||
if (structureType && structureType.indexOf("跨式") >= 0) {
|
|
||||||
return _.max(_.map(trades, x => Math.abs(x.InitialMargin)));
|
|
||||||
}
|
|
||||||
return _.reduce(trades, (acc, cur) => acc += parseFloat(cur.InitialMargin) || 0, 0);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
}
|
|
||||||
else if (PS.Config.Company == CompanyEnum.弘业)
|
|
||||||
{
|
|
||||||
<script>
|
|
||||||
pageVue.GetTotalMargin = function (trades, structureType) {
|
|
||||||
if (structureType && structureType.indexOf("跨式") >= 0) {
|
|
||||||
return _.max(_.map(trades, x => Math.abs(x.InitialMargin)));
|
|
||||||
}
|
|
||||||
return _.reduce(trades, (acc, cur) => acc += parseFloat(cur.InitialMargin) || 0, 0);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
}
|
|
||||||
|
|
||||||
<script src="~/Scripts/app/pricing/tradePricing_dz.js?v=@(HtmlUtil.JsVersion)"></script>
|
|
||||||
<script src="~/Scripts/app/pricing/structure_dz.js?v=@(HtmlUtil.JsVersion)"></script>
|
|
||||||
}
|
|
||||||
|
|
||||||
@await Html.PartialAsync("_CouponDayCount")
|
|
||||||
|
|
||||||
<div id="listdiv" class="@(Model.IsImport ? "sr-only" : "")">
|
|
||||||
|
|
||||||
<!--定价顶部-->
|
|
||||||
<div class="card pricing-top" id="pricing-top">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="row no-gutters">
|
|
||||||
<label class="col-auto mr-2">波动率类型</label>
|
|
||||||
<div class="col-auto mr-2">
|
|
||||||
<select v-model="viewState.VolType" v-on:change="pricingVue.changeVolType()">
|
|
||||||
@foreach (var item in ConsVolInfos.VolTypes)
|
|
||||||
{
|
|
||||||
<option value="@item">@item</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col" style="min-width:350px">
|
|
||||||
<div class="dropdown d-inline-block">
|
|
||||||
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">新增单腿</button>
|
|
||||||
<div class="dropdown-menu" style="width:200px;">
|
|
||||||
<a href="javascript:;" class="dropdown-item" v-for="item in optionTradeTypes" v-on:click="pricingVue.addTrade(null,item.value)">{{item.value}}</a>
|
|
||||||
<div class="dropdown-divider"></div>
|
|
||||||
<div class="form-group ml-2">
|
|
||||||
<div class="input-group">
|
|
||||||
<input type="text" class="form-control" id="importTradeNumber" placeholder="输入交易编号导入" />
|
|
||||||
<span class="input-group-append">
|
|
||||||
<a href="javascript:;" class="pl-2 pr-2" onclick="topVue.importTrade()"><i class="fa fa-copy"></i></a>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="dropdown d-inline-block">
|
|
||||||
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">新增组合</button>
|
|
||||||
<div class="dropdown-menu">
|
|
||||||
<a v-if="!simpleMode" href="javascript:;" class="dropdown-item" onclick="pricingVue.combine()">自由组合</a>
|
|
||||||
@foreach (var item in StructureOption_Code.StructureOptionsCn)
|
|
||||||
{
|
|
||||||
if (!new List<string>() { "复制标的资产", "比例价差", "箱式价差" }.Contains(item.Text))
|
|
||||||
{
|
|
||||||
<a class="dropdown-item" href="javascript:;" v-on:click="addStructure('@item.Value','@item.Text')">@item.Text</a>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button type="button" class="btn btn-primary" onclick="pricingVue.calcPrice()">定价计算</button>
|
|
||||||
@if (CurUser.交易管理_交易新增)
|
|
||||||
{
|
|
||||||
<button type="button" class="btn btn-primary" onclick="pricingVue.saveTrades()">录入交易</button>
|
|
||||||
}
|
|
||||||
<div class="dropdown d-inline-block">
|
|
||||||
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">图形分析</button>
|
|
||||||
<div class="dropdown-menu">
|
|
||||||
@*<a class="dropdown-item" href="javascript:;" v-on:click="pricingVue.showPayoffLineChart()">到期收益曲线</a>*@
|
|
||||||
@*<a class="dropdown-item" href="javascript:;" v-on:click="pricingVue.showPvChart()">组合价值曲线</a>*@
|
|
||||||
<a class="dropdown-item" href="javascript:;" v-on:click="pricingVue.showLifeLineChart()">Pv变化曲线</a>
|
|
||||||
<a class="dropdown-item" href="javascript:;" v-on:click="pricingVue.showGreeksChart()">时间变化曲线</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="btn-group">
|
|
||||||
<button type="button" class="btn btn-danger" onclick="templateVue.showList()">模板</button>
|
|
||||||
<button type="button" class="btn btn-danger" onclick="templateVue.showSave()" title="保存为模板">保存</button>
|
|
||||||
</div>
|
|
||||||
<div class="dropdown d-inline-block">
|
|
||||||
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">选项</button>
|
|
||||||
<div class="dropdown-menu">
|
|
||||||
<a class="dropdown-item" href="javascript:;" v-on:click="toggleSimpleMode" title="是否隐藏不常用的字段">
|
|
||||||
<span class="fa mr-2" v-bind:class="simpleMode?'fa-check':''"></span>
|
|
||||||
<span>精简模式</span>
|
|
||||||
</a>
|
|
||||||
@if (Model.ShowInitialMargin)
|
|
||||||
{
|
|
||||||
<a class="dropdown-item" href="javascript:;" v-on:click="toggleCalcMargin" title="是否计算初始预付金">
|
|
||||||
<span class="fa mr-2" v-bind:class="calcMargin?'fa-check':''"></span>
|
|
||||||
<span>计算预付金</span>
|
|
||||||
</a>
|
|
||||||
}
|
|
||||||
<a class="dropdown-item" href="javascript:;" v-on:click="toggleCalcAutocallGreeks" title="是否计算凤凰和雪球的所有Greeks">
|
|
||||||
<span class="fa mr-2" v-bind:class="calcAutocallGreeks?'fa-check':''"></span>
|
|
||||||
<span>计算凤凰和雪球的所有Greeks</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button type="button" class="btn btn-primary" onclick="pricingVue.clear()" title="清空legs交易">清空</button>
|
|
||||||
@if (CurUser.交易管理_分组设置)
|
|
||||||
{
|
|
||||||
<button type="button" class="btn btn-primary" onclick="pricingVue.saveGroupTrades()">加入分组</button>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="yc-panel">
|
|
||||||
<!--定价合计-->
|
|
||||||
<div class="pricing-summary" id="pricing-summary">
|
|
||||||
<table class="table table-bordered">
|
|
||||||
<colgroup>
|
|
||||||
<col span="1" width="200" />
|
|
||||||
<col span="1" width="150" />
|
|
||||||
</colgroup>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>对冲手数</th>
|
|
||||||
@*<th>组合成交金额</th>*@
|
|
||||||
<th v-if="topVue.calcMargin">组合预付金</th>
|
|
||||||
<th>Day1Pnl</th>
|
|
||||||
<th>PV</th>
|
|
||||||
<th>Delta</th>
|
|
||||||
<th>GammaCash</th>
|
|
||||||
<th>Theta</th>
|
|
||||||
<th>Vega</th>
|
|
||||||
<th>Rho</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody v-cloak>
|
|
||||||
<tr>
|
|
||||||
<td style="color:red;font-weight: bold;">
|
|
||||||
<span>{{DeltaHands}}</span>
|
|
||||||
@if (Model.HedgingOrder && Model.IsTrader)
|
|
||||||
{
|
|
||||||
<a href="javascript:;" class="ml-1" onclick="pricingVue.hedgingOrder()" title="对冲下单"><i class="fa fa-external-link"></i></a>
|
|
||||||
}
|
|
||||||
</td>
|
|
||||||
@*<td>{{summary.TotalTradePrice| FixNumber}}</td>*@
|
|
||||||
<td v-if="topVue.calcMargin">{{summary.TotalMargin| FixNumber}}</td>
|
|
||||||
<td>{{summary.TotalDay1Pnl| FixNumber}}</td>
|
|
||||||
<td>{{summary.Pv| FixNumber}}</td>
|
|
||||||
<td>{{summary.Delta| FixNumber}}</td>
|
|
||||||
<td>{{summary.GammaCash| FixNumber}}</td>
|
|
||||||
<td>{{summary.Theta| FixNumber}}</td>
|
|
||||||
<td>{{summary.Vega| FixNumber}}</td>
|
|
||||||
<td>{{summary.Rho| FixNumber}}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="clearfix"></div>
|
|
||||||
|
|
||||||
<!--定价列表-->
|
|
||||||
<div class="pricing-main">
|
|
||||||
<div class="d-flex">
|
|
||||||
<div class="pricing-titles-cont">
|
|
||||||
<div class="singleprice" id="singleprice">@(Model.CompanyName) 付 0.000</div>
|
|
||||||
<div class="pricing-titles">
|
|
||||||
<div>组合单价</div>
|
|
||||||
</div>
|
|
||||||
<div id="pricing-titles"></div>
|
|
||||||
</div>
|
|
||||||
<div class="pricing-items-cont">
|
|
||||||
<div class="zhanwei"></div>
|
|
||||||
<div class="d-flex" id="pricing-items"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--定价组件模板框架-->
|
|
||||||
<template id="pricingItems_tpl">
|
|
||||||
<div class="pricing-item">
|
|
||||||
<div class="pricing-index screenshot-hide" v-if="!pageVue.IsImport">
|
|
||||||
<span class="structure-type">{{structureType}}</span>
|
|
||||||
<a href="javascript:;" title="拖动位置" class="pricing-index-drag" v-show="!floating"><i class="fa fa-arrows"></i></a>
|
|
||||||
<a href="javascript:;" v-on:click="remove" title="移除此项" v-show="!floating"><i class="fa fa-remove"></i></a>
|
|
||||||
<a href="javascript:void(0)" class="pricing-index-text">{{index}}</a>
|
|
||||||
<div class="pricing-index-icons" v-show="!floating">
|
|
||||||
<label class="check-label">
|
|
||||||
<input type="checkbox" v-model="isSelected" v-on:change="resetSummary(true)">
|
|
||||||
</label>
|
|
||||||
<a href="javascript:;" v-on:click="saveTrade" title="录入交易"><i class="fa fa-save"></i></a>
|
|
||||||
<a href="javascript:;" v-show="showFloatingIcon" v-on:click="showFloatVue" title="浮窗编辑">
|
|
||||||
<i class="fa fa-external-link"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="pricing-index-right" v-show="!floating">
|
|
||||||
<div class="dropdown">
|
|
||||||
<a href="javascript:;" class="pricing-index-right-toggle" data-toggle="dropdown">
|
|
||||||
<i class="fa fa-ellipsis-v"></i>
|
|
||||||
</a>
|
|
||||||
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
|
|
||||||
<a href="javascript:;" class="dropdown-item" v-on:click="copyThis">复制此项</a>
|
|
||||||
<a href="javascript:;" class="dropdown-item" v-on:click="screenshot">生成截图</a>
|
|
||||||
<a href="javascript:;" class="dropdown-item" v-show="datas.length>1" v-on:click="uncouple">取消组合</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="pricing-trades">
|
|
||||||
<template v-for="(data,index) in datas">
|
|
||||||
<vue-trade2 v-if="data.trade.TradeType==='现金流交易'" v-on:reset-summary="resetSummary" v-on:change-client="changeClient" :floating="floating" :trade="data.trade" :view-state="data.viewState" :calc-result="data.calcResult"></vue-trade2>
|
|
||||||
<vue-trade v-else v-on:reset-summary="resetSummary" v-on:change-client="changeClient" v-on:synch-trade="synchTrade" v-on:sum-total="sumTotal" :floating="floating" :trade="data.trade" :view-state="data.viewState" :calc-result="data.calcResult"></vue-trade>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
<div class="border-0 text-center" v-show="!floating">
|
|
||||||
<label class="w-100 m-0">
|
|
||||||
<input type="checkbox" class="checkbox" v-model="isSelected" title="是否录入交易" v-on:change="resetSummary(true)" />
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!--定价组件模板内部-->
|
|
||||||
@await Html.PartialAsync("_PricingItemTpl_dz")
|
|
||||||
|
|
||||||
<!--定价浮窗-->
|
|
||||||
<div id="floatModal" class="modal modal-fullscreen @(Model.IsImport?"show":"")" tabindex="-1" data-backdrop="static">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="pricing-float-topbar">
|
|
||||||
<div class="btn-group screenshot-hide">
|
|
||||||
<button type="button" class="btn btn-primary" onclick="floatVue.screenshot()">截图</button>
|
|
||||||
<button type="button" class="btn btn-primary" onclick="floatVue.calcPrice()">定价计算</button>
|
|
||||||
<button type="button" class="btn btn-primary" onclick="floatVue.saveTrade()">录入交易</button>
|
|
||||||
<button type="button" class="btn btn-primary" onclick="floatVue.hide()">关闭</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="pricing-float-main d-flex" id="for-screenshot">
|
|
||||||
<div class="ml-auto pricing-titles-cont">
|
|
||||||
<div class="singleprice screenshot-hide" id="singleprice2">@(Model.CompanyName) 付 0.000</div>
|
|
||||||
<div class="pricing-titles screenshot-hide">
|
|
||||||
<div>组合单价</div>
|
|
||||||
</div>
|
|
||||||
<div id="pricing-titles2"></div>
|
|
||||||
</div>
|
|
||||||
<div class="mr-auto pricing-items-cont">
|
|
||||||
<div class="zhanwei screenshot-hide"></div>
|
|
||||||
<div class="pricing-float-items" id="pricing-items2"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--截图内容-->
|
|
||||||
<div id="screenshot" class="text-center screenshot-wrap" style="display:none;">
|
|
||||||
<div class="img-wrap">
|
|
||||||
<img id="screenshot-img" />
|
|
||||||
</div>
|
|
||||||
<div class="toolbar">
|
|
||||||
<button type="button" class="btn btn-primary" onclick="screenshoter.download()">保存截图</button>
|
|
||||||
<button type="button" class="btn btn-primary" onclick="screenshoter.closeShow()">关闭</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--标的下拉选择显示模板-->
|
|
||||||
<script type="text/html" id="underlyingSuggestionTpl">
|
|
||||||
<div class="row no-gutters" style="padding:3px 10px;">
|
|
||||||
<div class="col text-left">${Code}</div>
|
|
||||||
<% if (!!Name) { %>
|
|
||||||
<div class="col-auto text-right text-truncate" style="width:70px;">${Name}</div>
|
|
||||||
<% } %>
|
|
||||||
</div>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!--输入错误信息提示-->
|
|
||||||
<div class="modal" id="checkErrorModal" tabindex="-1" role="dialog">
|
|
||||||
<div class="modal-dialog" role="document">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">错误提示</h5>
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<table id="checkErrorTable" class="table table-bordered table-hover">
|
|
||||||
<colgroup>
|
|
||||||
<col span="1" width="100" />
|
|
||||||
</colgroup>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>编号</th>
|
|
||||||
<th>错误信息</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th>1</th>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">关闭</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--交易录入-->
|
|
||||||
<div class="modal" tabindex="-1" id="modalTradeSave" data-backdrop="static">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content" style="width:520px;">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">交易保存</h5>
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form class="mx-auto form-layout form-layout-save p-0 m-0 border-0" style="width:500px;border-radius:0;box-shadow:none">
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label">簿记账户</label>
|
|
||||||
<input type="text" class="form-input" id="AssetId" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label">交易员</label>
|
|
||||||
<input type="text" class="form-input" @(Model.CanSelectTrader ? "" : "readonly") id="TraderId" value="@(Model.Trade.TraderName)" data-id="@(Model.Trade.TraderId)" />
|
|
||||||
</div>
|
|
||||||
@if (!Model.ClientUsedForCalc)
|
|
||||||
{
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label">客户名称</label>
|
|
||||||
<input type="text" class="form-input" id="ClientId" />
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<div id="salesCommissionCtrl"></div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label">交易编号</label>
|
|
||||||
<input type="text" class="form-input @(Model.UpperTradeNumber?"text-uppercase":"")" id="TradeNumber" maxlength="50" autocomplete="off" placeholder="不填则自动生成" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@if (PS.Config.ErpElement.SecuritiesEnvironment)
|
|
||||||
{
|
|
||||||
<div class="form-group" hidden>
|
|
||||||
<label class="form-label">交易场所</label>
|
|
||||||
<select class="form-input" name="TradingPlace" id="TradingPlace">
|
|
||||||
@{
|
|
||||||
HtmlString html1 = new HtmlString("");
|
|
||||||
foreach (var item in YLErp.DBModels.Consts.ConsReport.TradingPlaceMap)
|
|
||||||
{
|
|
||||||
var str = "";
|
|
||||||
if (Model.Trade.MetaDic.ContainsKey("交易场所") && Model.Trade.MetaDic["交易场所"] == item.Key)
|
|
||||||
{
|
|
||||||
str = "selected='selected'";
|
|
||||||
}
|
|
||||||
<option @str>@item.Key</option>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group" hidden>
|
|
||||||
<label class="form-label">清算机构</label>
|
|
||||||
<select class="form-input" name="ClearingAgency" id="ClearingAgency">
|
|
||||||
@{
|
|
||||||
html1 = new HtmlString("");
|
|
||||||
foreach (var item in YLErp.DBModels.Consts.ConsReport.ClearingAgencyMap)
|
|
||||||
{
|
|
||||||
if (item.Key == "甲方" || item.Key == "乙方")
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
<option>@item.Key</option>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
if (!Model.ClientUsedForCalc)
|
|
||||||
{
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label">主协议编号</label>
|
|
||||||
<select class="form-input" name="MainProtocolCode" id="MainProtocolCode">
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="formlabel">补充协议编号</label>
|
|
||||||
<select class="form-input" name="SupProtocolCode" id="SupProtocolCode">
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="formlabel">中央对手方清算</label>
|
|
||||||
<select id="IsCentralClearing" class="form-input" name="IsCentralClearing">
|
|
||||||
<option value="N">否</option>
|
|
||||||
<option value="Y">是</option>
|
|
||||||
<option value="I">计划中央对手方清算</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="formlabel">中央清算平台</label>
|
|
||||||
<select id="CentralClearingPaltform" class="form-input" name="CentralClearingPaltform">
|
|
||||||
@foreach (var item in YLErp.BLL.DictionaryBLL.GetList("中央清算平台", true,"",true))
|
|
||||||
{
|
|
||||||
<option value="@item.Value">@item.Text</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="formlabel">交易平台</label>
|
|
||||||
<select id="TradingPaltform" class="form-input" name="TradingPaltform">
|
|
||||||
@foreach (var item in YLErp.BLL.DictionaryBLL.GetList("交易平台", true, "", true))
|
|
||||||
{
|
|
||||||
<option value="@item.Value">@item.Text</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div class="form-group" hidden>
|
|
||||||
<label class="form-label">交易对手方角色</label>
|
|
||||||
<select class="form-input" name="OpponentRole" id="OpponentRole">
|
|
||||||
<option>甲方</option>
|
|
||||||
<option selected>乙方</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
@if (PS.Config.Company == CompanyEnum.东方财富)
|
|
||||||
{
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="formlabel">初始预付金率</label>
|
|
||||||
<input type="number" class="form-input" id="InitialAdvance" />
|
|
||||||
<span>% </span>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="formlabel">期间预付金率</label>
|
|
||||||
<input type="number" class="form-input" id="PeriodAdvance" />
|
|
||||||
<span>% </span>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="formlabel">前端收益费率</label>
|
|
||||||
<input type="number" class="form-input" id="FontEarning" />
|
|
||||||
<span>% </span>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="formlabel">追保线</label>
|
|
||||||
<input type="number" class="form-input" id="ConfirmedLine" />
|
|
||||||
<span>% </span>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="formlabel">追保比例下限</label>
|
|
||||||
<input type="number" class="form-input" id="ConfirmedFloor" />
|
|
||||||
<span>% </span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<div class="mx-auto">
|
|
||||||
<button type="button" id="btnSave" class="btn btn-primary btn-save">录入交易</button>
|
|
||||||
<button type="button" class="btn btn-primary btn-close" data-dismiss="modal">关闭</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--加入组合-->
|
|
||||||
<div class="modal" tabindex="-1" id="modalGroupTradeSave" data-backdrop="static">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content" style="width:1020px;">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">组合交易保存</h5>
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form class="mx-auto form-layout form-layout-save p-0 m-0 border-0" style="width:990px;border-radius:0;box-shadow:none">
|
|
||||||
<div style="background-color: #F2F2F2; height: 15px; margin: unset;"></div>
|
|
||||||
<div style="background-color: #F2F2F2; height: 225px; margin: unset;">
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<label class="formlabel">交易日期</label>
|
|
||||||
<vue-datepicker class="text-box form-input" v-model="trade.TradeDate" disabled />
|
|
||||||
</div>
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<label class="formlabel">到期日期</label>
|
|
||||||
<vue-datepicker class="text-box form-input" v-model="trade.ExerciseDate" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<label class="formlabel">买卖方向</label>
|
|
||||||
<select class="form-input" v-model="trade.BuySell" v-on:change="changeBuySell()">
|
|
||||||
<option>卖出</option>
|
|
||||||
<option>买入</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<label class="formlabel">成交方式</label>
|
|
||||||
<select class="form-input" v-model="trade.IsUsePremiumRate" v-on:change="changeIsUsePremiumRate()">
|
|
||||||
<option :value="true">名义本金</option>
|
|
||||||
<option :value="false">成交数量</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<label class="formlabel">期初价格</label>
|
|
||||||
<vue-number-input class="form-input" v-model="trade.SpotPrice" v-bind:format="inputFormatSpot" disabled></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<label class="formlabel">成交数量</label>
|
|
||||||
<vue-number-input class="form-input" v-model="trade.TradeAmount" v-on:input="changeTradeAmount()" v-bind:format="inputFormatTradeAmount" v-bind:disabled="trade.IsUsePremiumRate"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<label class="formlabel">名义本金</label>
|
|
||||||
<vue-number-input class="form-input" v-model="trade.StockEqvNotional" v-on:input="changeStockEqvNotional()" v-bind:format="inputFormatEqvNotional" v-bind:disabled="!trade.IsUsePremiumRate"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<label class="formlabel">权利金</label>
|
|
||||||
<template v-if="trade.IsUsePremiumRate">
|
|
||||||
<vue-number-input class="form-input" v-model="trade.PremiumRate" v-bind:format="inputFormatPremiumRate" disabled></vue-number-input>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<vue-number-input class="form-input" v-model="trade.TradeSinglePrice" v-bind:format="inputFormatSinglePriceOnly" disabled></vue-number-input>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<label class="formlabel">交易总额</label>
|
|
||||||
<vue-number-input class="form-input" v-model="trade.TradePrice" disabled></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<label class="formlabel">相对行权价</label>
|
|
||||||
<select class="form-input" v-model="trade.IsMoneynessOption">
|
|
||||||
<option>是</option>
|
|
||||||
<option>否</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div style="background-color: #CDE0E6; height: 15px; margin: unset;"></div>
|
|
||||||
<div class="customPanel">
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<label class="form-label">结构类型</label>
|
|
||||||
<select class="form-input" v-model="trade.StructureType" v-on:change="changeStrucTureType()">
|
|
||||||
<option v-for="structureType in structureTypes">
|
|
||||||
{{ structureType }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<template v-if="trade.StructureType == '气囊结构'">
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<label class="formlabel">看涨看跌</label>
|
|
||||||
<select class="form-input" v-model="trade.OptionType">
|
|
||||||
<option>看涨</option>
|
|
||||||
<option>看跌</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<label class="formlabel">敲入价格</label>
|
|
||||||
<vue-number-input class="form-input" v-model="trade.trade_airbag.Barrier" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<label class="formlabel">低执行价格</label>
|
|
||||||
<vue-number-input class="form-input" v-model="trade.Strike" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<label class="formlabel">高执行价格</label>
|
|
||||||
<vue-number-input class="form-input" v-model="trade.trade_airbag.HighStrike" v-bind:format="inputFormatStrike" v-bind:disabled="!trade.trade_airbag.HasPayoffLimit"></vue-number-input>
|
|
||||||
<input type="checkbox" class="mr-1" v-model="trade.trade_airbag.HasPayoffLimit">
|
|
||||||
</div>
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<label class="formlabel">未敲入参与率</label>
|
|
||||||
<vue-number-input class="form-input" v-model="trade.trade_airbag.NotKIParticipationRate" v-bind:format="inputFormatPercent"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<label class="formlabel">上涨参与率</label>
|
|
||||||
<vue-number-input class="form-input" v-model="trade.trade_airbag.KIParticipationRate" v-bind:format="inputFormatPercent"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<template v-for="(value,key,index) in PropertyMap">
|
|
||||||
<template v-if="key != '气囊结构'">
|
|
||||||
<div v-show="trade.StructureType == key">
|
|
||||||
<template v-for="(item,index) in value">
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<template v-if="item.isNew">
|
|
||||||
<input type="text" class="form-input" style="width: 120px;" v-model="item.ColumnName" v-on:change="changeOption()" />
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<label class="formlabel">{{item.ColumnName}}</label>
|
|
||||||
</template>
|
|
||||||
<template v-if="item.ColumnType == @((int)YLErp.Enums.StructureColumnTypeEnum.NUMBER)">
|
|
||||||
<vue-number-input type="text" class="form-input" v-model="item.ColumnDefaultValue" v-bind:format="customNumberFormat"></vue-number-input>
|
|
||||||
</template>
|
|
||||||
<template v-else-if="item.ColumnType == @((int)YLErp.Enums.StructureColumnTypeEnum.NUMBERP)">
|
|
||||||
<vue-number-input type="text" class="form-input" v-model="item.ColumnDefaultValue" v-bind:format="customNumberPercentFormat"></vue-number-input>
|
|
||||||
</template>
|
|
||||||
<template v-else-if="item.ColumnType == @((int)YLErp.Enums.StructureColumnTypeEnum.DATE)">
|
|
||||||
<vue-datepicker class="text-box form-input" v-model="item.ColumnDefaultValue" />
|
|
||||||
</template>
|
|
||||||
<template v-else-if="item.ColumnType == @((int)YLErp.Enums.StructureColumnTypeEnum.COMBO_BOX_SINGLE)">
|
|
||||||
<select class="form-input" v-model="item.ColumnDefaultValue" autocomplete="off">
|
|
||||||
<option v-for="opt in item.ColumnOptions.split(',')" :value="opt" :key="opt">
|
|
||||||
{{opt}}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
@*YLErp.Enums.StructureColumnTypeEnum.TEXT*@
|
|
||||||
<input type="text" class="form-input" v-model="item.ColumnDefaultValue" />
|
|
||||||
</template>
|
|
||||||
<a class="fa fa-minus" style="margin-left: 10px;" v-on:click="deleteProperty(index)"></a>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
<div class="form-group col-6" style="text-align: center;">
|
|
||||||
<button type="button" class="btn btn-primary btn-save" v-on:click="addNewProperty()">新增</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
<div style="background-color: #F2F2F2; height: 15px; margin: unset;"></div>
|
|
||||||
<div style="background-color: #F2F2F2; height: 180px;">
|
|
||||||
<div style="margin-left: 15px;">
|
|
||||||
<label class='formlabel'>交易备注</label>
|
|
||||||
<textarea rows='3' v-model="trade.Comments" class="text-box h-auto text-left" style="width: 80%"></textarea>
|
|
||||||
</div>
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<label class="form-label">簿记账户</label>
|
|
||||||
<input type="text" class="form-input" id="GroupAssetId" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<label class="form-label">交易员</label>
|
|
||||||
<input type="text" class="form-input" id="GroupTraderId" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<label class="form-label">交易对手方</label>
|
|
||||||
<input type="text" class="form-input" id="GroupClientId" />
|
|
||||||
</div>
|
|
||||||
<div class="form-group col-6">
|
|
||||||
<label class="form-label">交易编号</label>
|
|
||||||
<input type="text" class="form-input" v-model="trade.TradeNumber" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@*@if (Model.SecuritiesEnvironment)
|
|
||||||
{
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label">交易场所</label>
|
|
||||||
<select class="form-input" v-model="trade.TradingPlace">
|
|
||||||
@foreach (var item in YLErp.DBModels.Consts.ConsReport.TradingPlaceMap)
|
|
||||||
{
|
|
||||||
<option>@item.Key</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label">清算机构</label>
|
|
||||||
<select class="form-input" v-model="trade.ClearingAgency">
|
|
||||||
@foreach (var item in YLErp.DBModels.Consts.ConsReport.ClearingAgencyMap)
|
|
||||||
{
|
|
||||||
if (item.Key == "甲方" || item.Key == "乙方")
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
<option>@item.Key</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
if (!Model.ClientUsedForCalc)
|
|
||||||
{
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="form-label">主协议编号</label>
|
|
||||||
<select class="form-input" name="MainProtocolCode" id="MainProtocolCode">
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="formlabel">补充协议编号</label>
|
|
||||||
<select class="form-input" name="SupProtocolCode" id="SupProtocolCode">
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
}*@
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<div class="mx-auto">
|
|
||||||
<button type="button" class="btn btn-primary btn-save" data-dismiss="modal" v-on:click="saveGroupTrade()">录入组合交易</button>
|
|
||||||
<button type="button" class="btn btn-primary btn-close" data-dismiss="modal">关闭</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--对冲下单-->
|
|
||||||
<form id="orderForm" action="/RiskHedging/HedgingOrder" method="post" target="_blank" class="sr-only">
|
|
||||||
<input type="hidden" name="InstType" value="" />
|
|
||||||
</form>
|
|
||||||
|
|
||||||
@await Html.PartialAsync("_SyntheticPrice")
|
|
||||||
@await Html.PartialAsync("/Views/trade/_part/SalesCommission.cshtml", new SalesCommissionModel() { Disabled = false, ViewType = "期权" })
|
|
||||||
|
|
||||||
<!--自定义模板-->
|
|
||||||
<div class="modal" tabindex="-1" id="modalTemplate">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">自定义模板</h5>
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<template v-if="saveMode">
|
|
||||||
<form id="formTemplateSave" onsubmit="return false;">
|
|
||||||
<div class="form-group">
|
|
||||||
<label>模板名称</label>
|
|
||||||
<input type="text" class="form-control text-left" style="width:100%;" maxlength="50" v-model="saveData.name">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<div><label><input type="checkbox" v-model="saveData._override" checked="" class="mr-1">覆盖已存在的模板</label></div>
|
|
||||||
<div>
|
|
||||||
<label><input type="checkbox" v-model="saveData._CommonTemplate" checked="" class="mr-1">保存为公共模板</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group text-center">
|
|
||||||
<button type="button" class="btn btn-primary" v-on:click="saveTemplate">保存模板</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<div class="yt-input-group d-inline-block">
|
|
||||||
<input type="text" class="search" v-model="searchText" placeholder="搜索" v-on:input="searchList" />
|
|
||||||
<a href="javascript:void(0)" class="yt-input-group-append show" v-on:click="searchList('reset')" style="padding-top:4px;" title="清除搜索"><i class="fa fa-remove"></i></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col text-right">
|
|
||||||
<a href="javascript:void(0)" v-on:click="refreshList" title="重新加载列表" style="line-height:30px;"><i class="fa fa-refresh"></i></a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr />
|
|
||||||
<ul class="list-group list-group-flush yt-template-group border">
|
|
||||||
<li class="list-group-item yt-template-item" v-for="item in listData" v-show="item.show">
|
|
||||||
<a href="javascript:void(0)" title="删除" class="yt-template-remove" v-on:click="removeTemplate(item.id)"><i class="fa fa-remove"></i></a>
|
|
||||||
<a href="javascript:void(0)" v-on:click="loadTemplate" class="yt-template-link">{{item.name}}</a><span>{{item.ConfigType==3?"公共模板":"个人模板"}}</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@@ -1,905 +0,0 @@
|
|||||||
@*定价模板*@
|
|
||||||
@model PricingModel
|
|
||||||
@{ Layout = null;}
|
|
||||||
|
|
||||||
<template id="pricingItem_tpl">
|
|
||||||
<div v-bind:class="isTitle?'pricing-titles':'pricing-trade'">
|
|
||||||
<div class="ptitle screenshot-hide" v-if="!pageVue.IsImport">交易序号</div>
|
|
||||||
|
|
||||||
<template v-if="pageVue.ClientUsedForCalc">
|
|
||||||
<div class="ptitle">客户名称</div>
|
|
||||||
<div class="pitem pitem-cash" v-show="!trade.hideCommen" v-bind:class="trade.hideCommen ? 'topborder' : ''">
|
|
||||||
<vue-client v-model="trade.ClientId" v-on:input="changeClient" :update="updateKey.client" />
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty" v-show="trade.hideCommen" v-bind:class="trade.hideCommen ? 'topborder' : ''"></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="ptitle">期权类型</div>
|
|
||||||
<div class="pitem" v-show="!trade.hideCommen">
|
|
||||||
<vue-tradetype v-model="trade.TradeType" v-on:input="changeTradeType" v-bind:disabled="!!trade.StructureType" />
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty" v-show="trade.hideCommen" v-bind:class="!pageVue.ClientUsedForCalc && trade.hideCommen ? 'topborder' : ''"></div>
|
|
||||||
<div class="pitem-cash">
|
|
||||||
<span>现金流</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<template v-if="!topVue.simpleMode" style="display:none">
|
|
||||||
<div class="ptitle screenshot-hide">标的类型</div>
|
|
||||||
<div class="pitem screenshot-hide" v-show="!trade.hideCommen">
|
|
||||||
<vue-niceselect name="UnderlyingInstrumentType" :items="tradeHelper.InstrumentTypes" v-model="trade.UnderlyingInstrumentType" v-on:input="changeInstrumentType" />
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty screenshot-hide" v-show="trade.hideCommen"></div>
|
|
||||||
<div class="pitem-cash screenshot-hide"></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="!topVue.simpleMode">
|
|
||||||
<div class="ptitle screenshot-hide">标的品种</div>
|
|
||||||
<div class="pitem screenshot-hide" v-show="!trade.hideCommen">
|
|
||||||
<vue-variety v-bind:variety="viewState.variety" v-on:change-variety="changeVariety" />
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty screenshot-hide" v-show="trade.hideCommen"></div>
|
|
||||||
<div class="pitem-cash screenshot-hide"></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="ptitle">标的代码</div>
|
|
||||||
<div class="pitem" v-show="!trade.hideCommen">
|
|
||||||
<vue-underlying v-bind:underlying="viewState.underlying" v-on:change-underlying="changeUnderlying" />
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty" v-show="trade.hideCommen"></div>
|
|
||||||
<div class="pitem-cash"></div>
|
|
||||||
|
|
||||||
<div class="ptitle">成交数量</div>
|
|
||||||
<div class="pitem" v-show="!trade.hideCommen || trade.StructureType == '蝶式组合'">
|
|
||||||
<vue-number-input v-model="trade.TradeAmountV" v-on:input="changeTradeAmountV" v-bind:format="inputFormatTradeAmountV" v-bind:disabled="!!trade.IsUsePremiumRate"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty" v-show="trade.hideCommen && trade.StructureType != '蝶式组合'"></div>
|
|
||||||
<div class="pitem-cash"></div>
|
|
||||||
|
|
||||||
<template v-if="!topVue.simpleMode">
|
|
||||||
<div class="ptitle screenshot-hide">有效成交数量</div>
|
|
||||||
<div class="pitem screenshot-hide" v-show="!trade.hideCommen || trade.StructureType == '蝶式组合'">
|
|
||||||
<vue-number-input v-model="trade.TradeAmount" v-on:input="changeTradeAmount" v-bind:format="inputFormatTradeAmount" v-bind:disabled="!!trade.IsUsePremiumRate"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty screenshot-hide" v-show="trade.hideCommen && trade.StructureType != '蝶式组合'"></div>
|
|
||||||
<div class="pitem-cash screenshot-hide"></div>
|
|
||||||
|
|
||||||
<div class="ptitle screenshot-hide">名义本金</div>
|
|
||||||
<div class="pitem pitem-cash screenshot-hide" v-show="!trade.hideCommen || trade.StructureType == '蝶式组合'">
|
|
||||||
<input type="number" v-bind:disabled="!trade.IsUsePremiumRate" v-model="trade.StockEqvNotional" v-on:change="changeStockEqvNotional" />
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty screenshot-hide" v-show="trade.hideCommen && trade.StructureType != '蝶式组合'"></div>
|
|
||||||
|
|
||||||
<div class="ptitle screenshot-hide">有效名义本金</div>
|
|
||||||
<div class="pitem pitem-cash screenshot-hide" v-show="!trade.hideCommen || trade.StructureType == '蝶式组合'">
|
|
||||||
<input type="number" v-bind:disabled="!trade.IsUsePremiumRate" v-model="trade.StockEqvNotionalReal" v-on:change="changeStockEqvNotionalReal" />
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty screenshot-hide" v-show="trade.hideCommen && trade.StructureType != '蝶式组合'"></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="!floating||fieldState.ExerciseMode">
|
|
||||||
<div class="ptitle">行权方式</div>
|
|
||||||
<div class="pitem" v-show="!trade.hideCommen">
|
|
||||||
<vue-niceselect name="ExerciseMode" :items="tradeHelper.ExerciseModes" v-model="trade.ExerciseMode" v-on:input="changeExerciseMode" v-if="showExerciseMode" v-bind:disabled="showExerciseMode===1" />
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty" v-bind:class="trade.StructureType == '蝶式组合' ? 'topborder' : ''" v-show="trade.hideCommen"></div>
|
|
||||||
<div class="pitem-cash"></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="ptitle">交易日期</div>
|
|
||||||
<div class="pitem pitem-cash" v-show="!trade.hideCommen">
|
|
||||||
<vue-datepicker :maxdate="trade.ExerciseDate" v-model="trade.TradeDate" :noholiday="fieldState.Cashflow" v-on:input="changeTradeDate" />
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty" v-show="trade.hideCommen"></div>
|
|
||||||
|
|
||||||
<div class="ptitle">到期日期</div>
|
|
||||||
<div class="pitem pitem-cash" v-show="!trade.hideCommen || trade.StructureType == '日历价差'">
|
|
||||||
<vue-datepicker :maxdate="trade.MaturityDate" v-model="trade.ExerciseDate" :noholiday="fieldState.Cashflow" v-on:input="changeExerciseDate" />
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty" v-show="trade.hideCommen && trade.StructureType != '日历价差'"></div>
|
|
||||||
|
|
||||||
<template v-if="!topVue.simpleMode">
|
|
||||||
<div class="ptitle screenshot-hide">结算日期</div>
|
|
||||||
<div class="pitem pitem-cash screenshot-hide" v-show="!trade.hideCommen || trade.StructureType == '日历价差'">
|
|
||||||
<vue-datepicker v-model="trade.SettlementDate" :noholiday="fieldState.Cashflow" v-on:input="changeSettlementDate" />
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty screenshot-hide" v-show="trade.hideCommen && trade.StructureType != '日历价差'"></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="ptitle">期初标的价格</div>
|
|
||||||
<div class="pitem seal" v-show="!trade.hideCommen">
|
|
||||||
<div class="yt-input-group" v-bind:class="viewState.SpotPrice">
|
|
||||||
<input type="number" class="has-popover-syn" v-model="trade.SpotPrice" v-on:input="changeSpotPrice(true)" v-on:blur="blurSpotPrice" v-bind:step="getPriceTick()" v-bind:readonly="!!viewState.synthetic" v-bind:data-calcid="trade.CalcId" max="999999" min="-999999" />
|
|
||||||
<a href="javascript:;" v-on:click="getSpotPrice" title="获取系统的期初标的价格" class="yt-input-group-append s1" tabindex="-1">
|
|
||||||
<i class="fa fa-refresh"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty" v-bind:class="trade.StructureType == '日历价差' ? 'topborder' : ''" v-show="trade.hideCommen"></div>
|
|
||||||
<div class="pitem-cash seal"><span class="sr-only">期初标的价格</span></div>
|
|
||||||
|
|
||||||
<template v-if="!topVue.simpleMode">
|
|
||||||
<div class="ptitle screenshot-hide">标的价格</div>
|
|
||||||
<div class="pitem seal screenshot-hide" v-show="!trade.hideCommen">
|
|
||||||
<div class="yt-input-group">
|
|
||||||
<input type="number" v-model="trade.UnderlyingPrice" v-on:input="synchTrade" max="999999" min="-999999" step="0.01" />
|
|
||||||
<a href="javascript:;" v-on:click="getUnderlyingPrice" title="获取系统的标的价格" class="yt-input-group-append s1" tabindex="-1">
|
|
||||||
<i class="fa fa-refresh"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty screenshot-hide" v-show="trade.hideCommen"></div>
|
|
||||||
<div class="pitem-cash seal screenshot-hide"><span class="sr-only">标的价格</span></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="ptitle" v-show="!floating||!fieldState.AutoCall&&!fieldState.SnowBall">执行价格</div>
|
|
||||||
<div class="pitem seal" v-show="!floating||!fieldState.AutoCall&&!fieldState.SnowBall">
|
|
||||||
<div class="yt-input-group" v-if="!fieldState.AutoCall&&!fieldState.SnowBall&&trade.StrikeType!=='Floating'">
|
|
||||||
<vue-number-input name="Strike" v-model="trade.Strike" v-on:input="changeStrike" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
<span class="yt-input-group-append" tabindex="-1">
|
|
||||||
<a href="javascript:;" v-if="trade.IsMoneynessOption==='是'" v-on:click="showAbsStrike" title="点击后切换成绝对值执行价格">%</a>
|
|
||||||
<a href="javascript:;" v-else v-on:click="showPercentStrike" title="点击后切换成标的价格百分比">¥</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="pitem-cash"><span class="sr-only">执行价格</span></div>
|
|
||||||
|
|
||||||
<template v-if="!floating||fieldState.OptionType">
|
|
||||||
<div class="ptitle">看涨看跌</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-niceselect name="OptionType" :items="tradeHelper.OptionTypes" v-model="trade.OptionType" v-if="showOptionType" />
|
|
||||||
</div>
|
|
||||||
<div class="pitem-cash"></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="ptitle">交易方向</div>
|
|
||||||
<div class="pitem pitem-cash">
|
|
||||||
<vue-niceselect name="BuySell" :items="consBuysellTypes" v-model="trade.BuySell" v-on:input="changeBuySell" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="ptitle">权利金</div>
|
|
||||||
<div class="pitem yt-input-group">
|
|
||||||
<template v-if="trade.IsUsePremiumRate">
|
|
||||||
<vue-number-input name="PremiumRate" v-model="trade.PremiumRate" v-on:input="changePremiumRate" v-bind:format="inputFormatPremiumRate"></vue-number-input>
|
|
||||||
<a href="javascript:;" title="点击后切换成绝对值权利金" v-on:click="showAbsPrice" class="yt-input-group-append" tabindex="-1">%</a>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<vue-number-input name="TradeSinglePrice" v-model="trade.TradeSinglePrice" v-on:input="changeTradeSinglePrice" v-bind:format="inputFormatSinglePriceOnly"></vue-number-input>
|
|
||||||
<a href="javascript:;" title="点击后切换成标的价格百分比" v-on:click="showPercentPrice" class="yt-input-group-append" tabindex="-1">¥</a>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
<div class="pitem-cash"></div>
|
|
||||||
|
|
||||||
<!--简单模式-->
|
|
||||||
<template v-if="!topVue.simpleMode">
|
|
||||||
<div class="ptitle screenshot-hide">参与率</div>
|
|
||||||
<div class="pitem screenshot-hide">
|
|
||||||
<vue-number-input v-model="trade.ParticipationRate" v-on:input="changeEffectRatio" v-bind:format="inputFormatPercent"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="pitem-cash screenshot-hide"></div>
|
|
||||||
|
|
||||||
<div class="ptitle screenshot-hide">保底收益</div>
|
|
||||||
<div class="pitem screenshot-hide">
|
|
||||||
<template v-if="trade.IsUsePremiumRate">
|
|
||||||
<vue-number-input name="PrincipalRateWrite" v-model="trade.PrincipalRateWrite" v-on:input="changeEffectRatio" v-bind:format="inputFormatPremiumRate"></vue-number-input>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<vue-number-input name="SinglePrincipalWrite" v-model="trade.SinglePrincipalWrite" v-on:input="changeEffectRatio" v-bind:format="inputFormatSinglePrincipalOnly"></vue-number-input>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
<div class="pitem-cash screenshot-hide"></div>
|
|
||||||
|
|
||||||
<div class="ptitle screenshot-hide">保底收益总额</div>
|
|
||||||
<div class="pitem yt-input-group screenshot-hide">
|
|
||||||
<vue-number-input name="OriginalPrincipalSum" v-model="trade.OriginalPrincipalSum" v-bind:format="inputFormatDouble2" v-on:input="changePrincipalSum"></vue-number-input>
|
|
||||||
<a href="javascript:;" v-on:click="changeEffectRatio" title="计算保底收益总额" class="yt-input-group-append s1" tabindex="-1">
|
|
||||||
<i class="fa fa-refresh"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="ptitle">成交金额</div>
|
|
||||||
<div class="pitem pitem-cash">
|
|
||||||
<vue-number-input v-model="trade.TradePrice" v-bind:disabled="!fieldState.Cashflow" v-bind:format="inputFormatTradePrice"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="pitem-cash"></div>
|
|
||||||
|
|
||||||
<!--初始预付金-->
|
|
||||||
@if (Model.ShowInitialMargin)
|
|
||||||
{
|
|
||||||
//组合交易初始预付金不需要展示,只需要展示组合预付金
|
|
||||||
<template v-if="topVue.calcMargin && !fieldState.ShowTotal">
|
|
||||||
<div class="ptitle">初始预付金</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<div class="yt-input-group" v-bind:class="viewState.InitialMargin">
|
|
||||||
<vue-number-input v-on:change="changeInitialMargin" v-model="trade.InitialMargin" v-bind:format="inputFormatTradePrice" step="0.1"></vue-number-input>
|
|
||||||
<a href="javascript:;" v-on:click="getInitialMargin" title="使用系统计算的初始预付金" class="yt-input-group-append s1">
|
|
||||||
<i class="fa fa-refresh"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="pitem-cash"></div>
|
|
||||||
</template>
|
|
||||||
}
|
|
||||||
|
|
||||||
<template v-if="fieldState.ShowTotal">
|
|
||||||
<div class="ptitle">组合价格</div>
|
|
||||||
<div class="pitem pitem-cash" v-show="!trade.hideCommen">
|
|
||||||
<vue-number-input v-model="trade.TotalTradePrice" v-bind:format="inputFormatTradePrice" disabled></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty topborder" v-show="trade.hideCommen"></div>
|
|
||||||
<div class="pitem-cash"></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
@if (Model.ShowInitialMargin)
|
|
||||||
{
|
|
||||||
<template v-if="topVue.calcMargin && fieldState.ShowTotal">
|
|
||||||
<div class="ptitle">组合预付金</div>
|
|
||||||
<div class="pitem" v-show="!trade.hideCommen">
|
|
||||||
<div class="yt-input-group" v-bind:class="viewState.InitialMargin">
|
|
||||||
<vue-number-input v-model="trade.TotalInitialMargin" v-bind:format="inputFormatTradePrice" disabled></vue-number-input>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty" v-show="trade.hideCommen"></div>
|
|
||||||
<div class="pitem-cash"></div>
|
|
||||||
</template>
|
|
||||||
}
|
|
||||||
|
|
||||||
<!--奇异期权-->
|
|
||||||
<template v-if="floating">
|
|
||||||
<!--------------二元期权---------------->
|
|
||||||
<template v-if="fieldState.BinaryOption">
|
|
||||||
<div class="ptitle">二元类型</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-niceselect name="PayoffType" :items="binaryPayoffTypes" v-model="trade.PayoffType" v-on:input="changePayoffType" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">补偿金额</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-number-input v-if="trade.IsUsePremiumRate" v-model="trade.CashOrNothingAmountRate" v-bind:format="inputFormatPremiumRate" v-bind:disabled="trade.PayoffType==='AssetOrNothing'"></vue-number-input>
|
|
||||||
<vue-number-input v-else v-model="trade.CashOrNothingAmount" v-bind:format="inputFormatSinglePrice" v-bind:disabled="trade.PayoffType==='AssetOrNothing'"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<template v-if="fieldState.ExerciseMode>10">
|
|
||||||
<template v-if="fieldState.PayoffTypeShow">
|
|
||||||
<div class="ptitle">高障碍价格</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-number-input v-model="trade.BarrierHigh" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">高障碍补偿金额</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<div>
|
|
||||||
<vue-number-input v-if="trade.IsUsePremiumRate" v-model="trade.CashOrNothingAmountHighRate" v-bind:format="inputFormatPremiumRate" v-bind:disabled="trade.PayoffType=='DoubleNoTouch'&&trade.ExerciseMode=='American'"></vue-number-input>
|
|
||||||
<vue-number-input v-else v-model="trade.CashOrNothingAmountHigh" v-bind:format="inputFormatSinglePrice" v-bind:disabled="trade.PayoffType=='DoubleNoTouch'&&trade.ExerciseMode=='American'"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<div class="ptitle">观察方式</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-niceselect name="MonitorType" :items="consMonitorTypes" v-model="trade.MonitorType" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">补偿支付</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-niceselect name="RebateType" :items="binaryRebateTypes" v-model="trade.RebateType" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<div class="ptitle">补偿按敲出日年化</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-niceselect name="RebateAnnualizedAtKO" :items="consFalseAsNo" v-model="trade.RebateAnnualizedAtKO" v-bind:disabled="trade.ExerciseMode === 'European' || this.trade.PayoffType === 'UpNoTouch' || this.trade.PayoffType === 'DownNoTouch' || this.trade.PayoffType === 'DoubleNoTouch'" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">补偿计息规则</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-daycount v-if="trade.RebateAnnualizedAtKO" name="RebateDayCount" v-model="trade.RebateDayCount" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<!--------------障碍期权---------------->
|
|
||||||
<template v-if="fieldState.BarrierOption">
|
|
||||||
<div class="ptitle">障碍类型</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-niceselect name="BarrierType" :items="consBarrierTypes" v-model="trade.BarrierType" v-on:input="changeFieldState" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">障碍价格</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-number-input v-model="trade.BarrierLow" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">高障碍价格</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-number-input v-if="(trade.BarrierType || '').startsWith('双')" v-model="trade.BarrierHigh" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">补偿金额</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-number-input v-if="trade.IsUsePremiumRate" v-model="trade.RebateRate" v-bind:format="inputFormatPremiumRate"></vue-number-input>
|
|
||||||
<vue-number-input v-else v-model="trade.Rebate" v-bind:format="inputFormatSinglePrice"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle" v-show="fieldState.IsBarrierType">高障碍补偿金额</div>
|
|
||||||
<div class="pitem" v-show="fieldState.IsBarrierType">
|
|
||||||
<vue-number-input v-if="trade.IsUsePremiumRate" v-model="trade.RebateHighRate" v-bind:format="inputFormatPremiumRate"></vue-number-input>
|
|
||||||
<vue-number-input v-else v-model="trade.RebateHigh" v-bind:format="inputFormatSinglePrice"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">障碍偏移</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<input type="number" v-model="trade.BarrierShift" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">观察方式</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-niceselect name="MonitorType" :items="consMonitorTypes" v-model="trade.MonitorType" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">补偿支付</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-niceselect name="RebateType" :items="consRebateTypes" v-model="trade.RebateType" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">补偿按敲出日年化</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-niceselect v-if="(trade.BarrierType || '').endsWith('敲出')" name="RebateAnnualizedAtKO" :items="consFalseAsNo" v-model="trade.RebateAnnualizedAtKO" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">补偿计息规则</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-daycount v-if="trade.RebateAnnualizedAtKO" name="RebateDayCount" v-model="trade.RebateDayCount" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<!--------------双鲨期权---------------->
|
|
||||||
<template v-if="fieldState.DBSharkOption">
|
|
||||||
<div class="ptitle">障碍价格</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-number-input v-model="trade.BarrierLow" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">高障碍价格</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-number-input v-model="trade.BarrierHigh" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">高行权价</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-number-input v-model="trade.StrikeHigh" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">补偿金额</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-number-input v-if="trade.IsUsePremiumRate" v-model="trade.RebateRate" v-bind:format="inputFormatPremiumRate"></vue-number-input>
|
|
||||||
<vue-number-input v-else v-model="trade.Rebate" v-bind:format="inputFormatSinglePrice"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">高障碍补偿金额</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-number-input v-if="trade.IsUsePremiumRate" v-model="trade.RebateHighRate" v-bind:format="inputFormatPremiumRate"></vue-number-input>
|
|
||||||
<vue-number-input v-else v-model="trade.RebateHigh" v-bind:format="inputFormatSinglePrice"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">高参与率</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-number-input v-model="trade.CallParticipationRate" v-bind:format="inputFormatPercent"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">低参与率</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-number-input v-model="trade.PutParticipationRate" v-bind:format="inputFormatPercent"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">观察方式</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-niceselect name="MonitorType" :items="consMonitorTypes" v-model="trade.MonitorType" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="ptitle">补偿支付</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-niceselect name="RebateType" :items="consRebateTypes" v-model="trade.RebateType" />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<!--------------亚式期权---------------->
|
|
||||||
<template v-if="fieldState.AsiaOption">
|
|
||||||
<div class="ptitle">均价起算日</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-datepicker v-model="trade.AveragingPeriodStartDate" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">均价计算</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-niceselect name="PayoffType" :items="consAsiaPayoffType" v-model="trade.PayoffType" v-on:input="changePayOffType" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle" id="EnhancedPriceTitle" v-show="trade.PayoffType=='EnhancedArithmeticAverage'&&trade.StrikeType!='Floating'">增强价格</div>
|
|
||||||
<div class="pitem" v-show="trade.PayoffType=='EnhancedArithmeticAverage'&&trade.StrikeType!='Floating'">
|
|
||||||
<vue-number-input v-model="trade.EnhancedPrice" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">行权价类型</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-niceselect name="StrikeType" :items="consAsiaStrikeType" v-model="trade.StrikeType" v-on:input="changeStrikeType" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">杠杆率</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-number-input v-model="trade.StrikeGearingFactor" v-bind:format="inputFormatPercent"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<!----------------雪球期权---------------->
|
|
||||||
<template v-if="fieldState.SnowBall">
|
|
||||||
<!---雪球期权敲出--->
|
|
||||||
<div class="ptitle">敲出障碍价格</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<div class="yt-input-group">
|
|
||||||
<vue-number-input v-model="trade.KOBarrier" v-on:input="changeKOBarrier" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
<span class="yt-input-group-append">
|
|
||||||
<a href="javascript:;" v-if="trade.IsMoneynessOption==='是'" v-on:click="showAbsStrike" title="点击后切换成绝对值执行价格" tabindex="-1">%</a>
|
|
||||||
<a href="javascript:;" v-else v-on:click="showPercentStrike" title="点击后切换成标的价格百分比" tabindex="-1">¥</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">敲出赔付类别</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-niceselect name="KOPayoffType" :items="snowballKOPayoffTypeEnums" v-model="trade.KOPayoffType" v-on:input="changeFieldState" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle" v-show="fieldState.IsFixedCoupon">票息年化</div>
|
|
||||||
<div class="pitem" v-show="fieldState.IsFixedCoupon">
|
|
||||||
<vue-niceselect name="IsFixedCoupon" :items="consFalseAsYes" v-model="trade.IsFixedCoupon" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle" v-show="fieldState.KORebate">票息率</div>
|
|
||||||
<div class="pitem yt-input-group" v-show="fieldState.KORebate">
|
|
||||||
<div><vue-number-input v-model="trade.KORebate" v-on:input="changeRebate" v-bind:format="inputFormatPremiumRate"></vue-number-input></div>
|
|
||||||
<a href="javascript:;" v-on:click="calcKORebate()" class="yt-input-group-append" tabindex="-1">
|
|
||||||
<span title="根据权利金反算票息" class="fa fa-refresh"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle" v-show="fieldState.IsFixedCoupon">票息日历规则</div>
|
|
||||||
<div class="pitem" v-show="fieldState.IsFixedCoupon">
|
|
||||||
<vue-daycount name="CouponDayCount" v-model="trade.CouponDayCount" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle" v-show="fieldState.KORebate">票息包含首日</div>
|
|
||||||
<div class="pitem" v-show="fieldState.KORebate">
|
|
||||||
<vue-niceselect name="CouponIncludeStartDate" :items="consFalseAsNo" v-model="trade.CouponIncludeStartDate" v-once />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle" v-show="fieldState.KORebate">使用支付日计息</div>
|
|
||||||
<div class="pitem" v-show="fieldState.KORebate">
|
|
||||||
<vue-niceselect name="CouponUsePaymentDate" :items="consFalseAsNo" v-model="trade.CouponUsePaymentDate" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle" v-show="fieldState.AnnualizedPremiumRate">年化期权费率</div>
|
|
||||||
<div class="pitem yt-input-group " v-show="fieldState.AnnualizedPremiumRate">
|
|
||||||
<div><vue-number-input v-model="trade.AnnualizedPremiumRate" v-bind:format="inputFormatPremiumRate"></vue-number-input></div>
|
|
||||||
<a href="javascript:;" v-on:click="calcSnowballAnnualPremium()" class="yt-input-group-append" tabindex="-1">
|
|
||||||
<span title="保本雪球计算年化期权费率" class="fa fa-refresh"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle" v-show="fieldState.SpreadStrikeAtKO1">敲出行权价1</div>
|
|
||||||
<div class="pitem" v-show="fieldState.SpreadStrikeAtKO1">
|
|
||||||
<vue-number-input v-model="trade.SpreadStrikeAtKO1" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle" v-show="fieldState.SpreadStrikeAtKO">敲出行权价2</div>
|
|
||||||
<div class="pitem" v-show="fieldState.SpreadStrikeAtKO">
|
|
||||||
<vue-number-input v-model="trade.SpreadStrikeAtKO" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">敲出支付方式</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-niceselect name="KORebateType" :items="consKORebateTypes" v-model="trade.KORebateType" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle screenshot-hide">敲出观察频率</div>
|
|
||||||
<div class="pitem screenshot-hide">
|
|
||||||
<div class="yt-input-group">
|
|
||||||
<input type="text" v-model="koObservationRate" readonly />
|
|
||||||
<a href="javascript:;" class="yt-input-group-append show" title="设置观察日" v-on:click="setObservationDates('#KO')" tabindex="-1">
|
|
||||||
<i class="fa fa-pencil-square"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!---雪球期权敲入--->
|
|
||||||
<div class="ptitle screenshot-hide">敲入观察频率</div>
|
|
||||||
<div class="pitem screenshot-hide">
|
|
||||||
<div class="yt-input-group">
|
|
||||||
<input type="text" v-model="observationRate" readonly />
|
|
||||||
<a href="javascript:;" class="yt-input-group-append show" title="设置观察日" v-on:click="setObservationDates('#KI')" tabindex="-1">
|
|
||||||
<i class="fa fa-pencil-square"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">敲入障碍价格</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<div class="yt-input-group">
|
|
||||||
<vue-number-input v-model="trade.KIBarrier" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
<span class="yt-input-group-append">
|
|
||||||
<a href="javascript:;" v-if="trade.IsMoneynessOption==='是'" v-on:click="showAbsStrike" title="点击后切换成绝对值执行价格" tabindex="-1">%</a>
|
|
||||||
<a href="javascript:;" v-else v-on:click="showPercentStrike" title="点击后切换成标的价格百分比" tabindex="-1">¥</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">敲入到期支付类别</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-niceselect name="KIPayoffType" :items="snowballKIPayoffTypeEnums" v-model="trade.KIPayoffType" v-on:input="changeFieldState" :key="updateKey.KIPayoffType" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle" v-show="fieldState.SpreadStrike1">敲入行权价</div>
|
|
||||||
<div class="pitem" v-show="fieldState.SpreadStrike1">
|
|
||||||
<vue-number-input v-model="trade.SpreadStrike1" v-bind:format="inputFormatStrike" v-on:input="changeSpreadStrike1"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle" v-show="fieldState.SpreadStrike">封底/封顶行权价</div>
|
|
||||||
<div class="pitem" v-show="fieldState.SpreadStrike">
|
|
||||||
<vue-number-input v-model="trade.SpreadStrike" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">红利票息</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-number-input v-model="trade.Coupon" v-bind:format="inputFormatPremiumRate"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<!--------------凤凰期权---------------->
|
|
||||||
<template v-if="fieldState.AutoCall">
|
|
||||||
<div class="ptitle">票息年化</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-niceselect name="IsFixedCoupon" :items="consFalseAsYes" v-model="trade.IsFixedCoupon" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">票息率</div>
|
|
||||||
<div class="pitem yt-input-group">
|
|
||||||
<vue-number-input name="Coupon" v-model="trade.Coupon" v-on:input="changeRebate" v-bind:format="inputFormatPremiumRate"></vue-number-input>
|
|
||||||
<a href="javascript:;" v-on:click="calcPhoenixCouponRate()" class="yt-input-group-append" tabindex="-1">
|
|
||||||
<span title="根据权利金反算票息" class="fa fa-refresh"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">票息障碍价格</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<div class="yt-input-group">
|
|
||||||
<vue-number-input v-model="trade.CouponBarrier" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
<span class="yt-input-group-append">
|
|
||||||
<a href="javascript:;" v-if="trade.IsMoneynessOption==='是'" v-on:click="showAbsStrike" title="点击后切换成绝对值执行价格" tabindex="-1">%</a>
|
|
||||||
<a href="javascript:;" v-else v-on:click="showPercentStrike" title="点击后切换成标的价格百分比" tabindex="-1">¥</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">票息日历规则</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-daycount name="CouponDayCount" v-model="trade.CouponDayCount" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">票息包含首日</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-niceselect name="CouponIncludeStartDate" :items="consFalseAsNo" v-model="trade.CouponIncludeStartDate" v-once />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">票息结算方式</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-niceselect name="CouponPayType" :items="consCouponPayTypes" v-model="trade.CouponPayType" v-on:input="changeCouponPayType" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">敲出障碍价格</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<div class="yt-input-group">
|
|
||||||
<vue-number-input v-model="trade.KOBarrier" v-on:input="changeKOBarrier" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
<span class="yt-input-group-append">
|
|
||||||
<a href="javascript:;" v-if="trade.IsMoneynessOption==='是'" v-on:click="showAbsStrike" title="点击后切换成绝对值执行价格" tabindex="-1">%</a>
|
|
||||||
<a href="javascript:;" v-else v-on:click="showPercentStrike" title="点击后切换成标的价格百分比" tabindex="-1">¥</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle screenshot-hide">敲出观察频率</div>
|
|
||||||
<div class="pitem screenshot-hide">
|
|
||||||
<div class="yt-input-group">
|
|
||||||
<input type="text" v-model="koObservationRate" readonly />
|
|
||||||
<a href="javascript:;" class="yt-input-group-append show" title="设置观察日" v-on:click="setObservationDates('#KO')" tabindex="-1">
|
|
||||||
<i class="fa fa-pencil-square"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle screenshot-hide">敲入观察频率</div>
|
|
||||||
<div class="pitem screenshot-hide">
|
|
||||||
<div class="yt-input-group">
|
|
||||||
<input type="text" v-model="observationRate" readonly />
|
|
||||||
<a href="javascript:;" class="yt-input-group-append show" title="设置观察日" v-on:click="setObservationDates('#KI')" tabindex="-1">
|
|
||||||
<i class="fa fa-pencil-square"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">敲入障碍价格</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<div class="yt-input-group">
|
|
||||||
<vue-number-input v-model="trade.KIBarrier" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
<span class="yt-input-group-append">
|
|
||||||
<a href="javascript:;" v-if="trade.IsMoneynessOption==='是'" v-on:click="showAbsStrike" title="点击后切换成绝对值执行价格" tabindex="-1">%</a>
|
|
||||||
<a href="javascript:;" v-else v-on:click="showPercentStrike" title="点击后切换成标的价格百分比" tabindex="-1">¥</a>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">敲入到期是否支付票息</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<div v-if="trade.CouponPayType===2">
|
|
||||||
<vue-niceselect name="IncludeCouponAfterKI" :items="consTrueAsYes" v-model="trade.IncludeCouponAfterKI" />
|
|
||||||
</div>
|
|
||||||
<div v-else>是</div>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">敲入到期支付类别</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-niceselect name="KIPayoffType" :items="autocallKIPayoffTypeEnums" v-model="trade.KIPayoffType" v-on:input="changeFieldState" :key="updateKey.KIPayoffType" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle" v-show="fieldState.SpreadStrike1">敲入行权价</div>
|
|
||||||
<div class="pitem" v-show="fieldState.SpreadStrike1">
|
|
||||||
<vue-number-input v-model="trade.SpreadStrike1" v-bind:format="inputFormatStrike" v-on:input="changeSpreadStrike1"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle" v-show="fieldState.SpreadStrike">封顶/封底行权价</div>
|
|
||||||
<div class="pitem" v-show="fieldState.SpreadStrike">
|
|
||||||
<vue-number-input v-model="trade.SpreadStrike" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<!--------------区间累计---------------->
|
|
||||||
<template v-if="fieldState.RangeAcc">
|
|
||||||
<div class="ptitle">区间下限</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-number-input v-model="trade.LowerRange" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">区间上限</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-number-input v-model="trade.UpperRange" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">区间收益</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-number-input v-model="trade.BonusRate" v-bind:format="inputFormatPercent4"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<!--------------气囊结构---------------->
|
|
||||||
<template v-if="fieldState.AirBag">
|
|
||||||
<div class="ptitle">障碍价格</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-number-input v-model="trade.BarrierLow" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">观察方式</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-niceselect name="IsDiscreteMonitored" :items="consIsDiscreteMonitored" v-model="trade.IsDiscreteMonitored" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">敲入参与率</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-number-input v-model="trade.KIParticipationRate" v-bind:format="inputFormatPercent"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">收益封顶</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-niceselect name="HasPayoffLimit" :items="consTrueAsYes" v-model="trade.HasPayoffLimit" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">收益封顶价格</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-number-input v-model="trade.HighStrike" v-bind:format="inputFormatStrike"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<!--------------收益增强结构---------------->
|
|
||||||
<template v-if="fieldState.UnEnhance">
|
|
||||||
<div class="ptitle">年化增强收益</div>
|
|
||||||
<div class="pitem">
|
|
||||||
<vue-number-input v-model="trade.AnnualizedEnhanceRate" v-bind:format="inputFormatPercent"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<!--------------现金流交易-------------->
|
|
||||||
<template v-if="fieldState.Cashflow">
|
|
||||||
<div class="ptitle">利率</div>
|
|
||||||
<div class="pitem-cash">
|
|
||||||
<vue-number-input name="ProfitRate" v-model="trade.ProfitRate" v-bind:format="inputFormatPremiumRate"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">资金类型</div>
|
|
||||||
<div class="pitem-cash">
|
|
||||||
<vue-niceselect name="DepositType" :items="consDepositType" v-model="trade.DepositType" v-on:input="changeDepositType" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">利率类型</div>
|
|
||||||
<div class="pitem-cash">
|
|
||||||
<vue-niceselect name="RateType" :items="consRateType" v-model="trade.RateType" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">计算日历规则</div>
|
|
||||||
<div class="pitem-cash">
|
|
||||||
<vue-daycount name="CouponDayCount" v-model="trade.CouponDayCount" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle">预付返还比例</div>
|
|
||||||
<div class="pitem-cash">
|
|
||||||
<vue-number-input v-show="trade.DepositType=='0'" name="PrepayRatio" v-model="trade.PrepayRatio" v-bind:format="inputFormatPremiumRate"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<!--------------观察频率---------------->
|
|
||||||
<template v-if="fieldState.ObservationDatesShow">
|
|
||||||
<div class="ptitle screenshot-hide">观察频率</div>
|
|
||||||
<div class="pitem screenshot-hide">
|
|
||||||
<div class="yt-input-group" v-if="trade.TradeType!=='二元期权'||(trade.TradeType==='二元期权'&&trade.ExerciseMode === 'American')">
|
|
||||||
<input type="text" v-model="observationRate" readonly />
|
|
||||||
<a href="javascript:;" class="yt-input-group-append show" title="设置观察日" v-on:click="setObservationDates('#KI')">
|
|
||||||
<i class="fa fa-pencil-square"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="ptitle screenshot-hide">成交波动率</div>
|
|
||||||
<div class="pitem screenshot-hide yt-input-group" v-bind:class="viewState.VolState">
|
|
||||||
<vue-number-input v-model="trade.Vol" v-bind:format="inputFormatVolPercent" v-on:input="changeOpenVolatility"></vue-number-input>
|
|
||||||
<a href="javascript:;" v-on:click="getTradeOpenVolatility" title="更新波动率" class="yt-input-group-append" tabindex="-1">
|
|
||||||
<i class="fa fa-refresh"></i>
|
|
||||||
</a>
|
|
||||||
<a href="javascript:;" v-on:click="getTradeImpliedVol" title="计算隐含波动率" class="yt-input-group-append s1" tabindex="-1" v-show="trade.TradeType==='香草期权'">
|
|
||||||
<i class="fa fa-calculator"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="pitem-cash screenshot-hide"></div>
|
|
||||||
|
|
||||||
<div class="ptitle screenshot-hide">Mid Vol</div>
|
|
||||||
<div class="pitem screenshot-hide yt-input-group" v-bind:class="viewState.MidVolState">
|
|
||||||
<vue-number-input v-model="trade.MidVol" v-bind:format="inputFormatVolPercent" v-on:input="changeOpenMidVolatility"></vue-number-input>
|
|
||||||
<a href="javascript:;" v-on:click="getTradeMidVolatility" title="更新Mid Vol" class="yt-input-group-append" tabindex="-1">
|
|
||||||
<i class="fa fa-refresh"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="pitem-cash screenshot-hide"></div>
|
|
||||||
|
|
||||||
<div class="ptitle screenshot-hide">Day1 Pnl</div>
|
|
||||||
<div class="pitem pitem-cash screenshot-hide">
|
|
||||||
<input type="number" v-model="trade.Day1Pnl" v-bind:format="inputFormatVolPercent" disabled />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--收益结算-->
|
|
||||||
<template v-if="!topVue.simpleMode">
|
|
||||||
<div class="ptitle screenshot-hide">收益结算</div>
|
|
||||||
<div class="pitem screenshot-hide" v-show="!trade.hideCommen">
|
|
||||||
<vue-niceselect name="SettlementType" :items="tradeHelper.SettlementTypes" v-model="trade.SettlementType" v-on:input="synchTrade" />
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty topborder screenshot-hide" v-show="trade.hideCommen"></div>
|
|
||||||
<div class="pitem-cash screenshot-hide"></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="!topVue.simpleMode">
|
|
||||||
<div class="ptitle screenshot-hide">无风险利率</div>
|
|
||||||
<div class="pitem pitem-cash yt-input-group screenshot-hide" v-bind:class="viewState.NoRiskRate" v-show="!trade.hideCommen">
|
|
||||||
<vue-number-input v-model="trade.NoRiskRate" v-on:input="changeNoRiskRate" v-bind:format="inputFormatPercent"></vue-number-input>
|
|
||||||
<a href="javascript:;" v-on:click="getNoRiskRate" class="yt-input-group-append" tabindex="-1">
|
|
||||||
<span title="获取系统设定的无风险利率" class="fa fa-refresh"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty screenshot-hide" v-show="trade.hideCommen"></div>
|
|
||||||
|
|
||||||
<template v-if="!floating&&fieldState.DividendRate">
|
|
||||||
<div class="ptitle screenshot-hide">分红率</div>
|
|
||||||
<div class="pitem screenshot-hide" v-show="!trade.hideCommen">
|
|
||||||
<div class="yt-input-group" v-bind:class="viewState.DividendRate" v-if="trade.UnderlyingInstrumentType==='Stock'||trade.UnderlyingInstrumentType==='StockIndex'">
|
|
||||||
<vue-number-input v-model="trade.DividendRate" v-on:input="changeDividendRate" v-bind:format="inputFormatPercentN"></vue-number-input>
|
|
||||||
<a href="javascript:;" v-on:click="getDividendRate" class="yt-input-group-append" tabindex="-1">
|
|
||||||
<span title="获取系统设定的分红率" class="fa fa-refresh"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty screenshot-hide" v-show="trade.hideCommen"></div>
|
|
||||||
<div class="pitem-cash screenshot-hide"></div>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="ptitle screenshot-hide">TTM(Days)</div>
|
|
||||||
<div class="pitem yt-input-group screenshot-hide" v-bind:class="viewState.TTMDays" v-show="!trade.hideCommen">
|
|
||||||
<input type="number" min="0" v-on:change="changeTTM" v-model="trade.TTMDays" />
|
|
||||||
<a href="javascript:;" v-on:click="getTTM(true)" class="yt-input-group-append s1" tabindex="-1">
|
|
||||||
<span title="获取交易日期和到期日期之间工作日的长度" class="fa fa-refresh"></span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty screenshot-hide" v-show="trade.hideCommen"></div>
|
|
||||||
<div class="pitem-cash screenshot-hide"></div>
|
|
||||||
|
|
||||||
<!--------------结构化产品-------------->
|
|
||||||
<template v-if="floating">
|
|
||||||
<template v-if="fieldState.Structure">
|
|
||||||
<div class="ptitle screenshot-hide">结算类型</div>
|
|
||||||
<div class="pitem screenshot-hide">
|
|
||||||
<vue-niceselect :items="consCashAsPhysical" v-model="viewState.CashOrPhysical" v-on:input="setcashOrPhysical" />
|
|
||||||
</div>
|
|
||||||
<div class="ptitle screenshot-hide">结构要素</div>
|
|
||||||
<div class="pitem screenshot-hide">
|
|
||||||
<div class="yt-input-group">
|
|
||||||
<input type="text" v-model="structure" />
|
|
||||||
<a href="javascript:;" class="yt-input-group-append show" title="结构要素" v-on:click="setStructureList()" tabindex="-1">
|
|
||||||
<i class="fa fa-pencil-square"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="ptitle screenshot-hide">观察日</div>
|
|
||||||
<div class="pitem screenshot-hide">
|
|
||||||
<div class="yt-input-group">
|
|
||||||
<input type="text" v-model="observationRate" readonly />
|
|
||||||
<a href="javascript:;" class="yt-input-group-append show" title="设置观察日" v-on:click="setObservationDates('#ST')" tabindex="-1">
|
|
||||||
<i class="fa fa-pencil-square"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="ptitle screenshot-hide">工作日</div>
|
|
||||||
<div class="pitem pitem-cash screenshot-hide" v-show="!trade.hideCommen">
|
|
||||||
<input type="number" v-model="trade.Weekdays" disabled />
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty screenshot-hide" v-show="trade.hideCommen"></div>
|
|
||||||
|
|
||||||
<div class="ptitle screenshot-hide">交易日</div>
|
|
||||||
<div class="pitem pitem-cash screenshot-hide" v-show="!trade.hideCommen">
|
|
||||||
<input type="number" v-model="trade.TradingDays" disabled />
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty screenshot-hide" v-show="trade.hideCommen"></div>
|
|
||||||
|
|
||||||
<div class="ptitle screenshot-hide">公共假日</div>
|
|
||||||
<div class="pitem pitem-cash screenshot-hide" v-show="!trade.hideCommen">
|
|
||||||
<input type="number" v-model="trade.PublicHolidays" disabled />
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty screenshot-hide" v-show="trade.hideCommen"></div>
|
|
||||||
|
|
||||||
<!--年化系数-->
|
|
||||||
<template v-if="!topVue.simpleMode">
|
|
||||||
<template v-if="fieldState.SnowBall||fieldState.AutoCall">
|
|
||||||
<div class="ptitle screenshot-hide">是否年化</div>
|
|
||||||
<div class="pitem screenshot-hide" v-show="!trade.hideCommen">
|
|
||||||
<vue-niceselect name="IsAnnualized2" :items="consFalseAsNo" v-model="trade.IsAnnualized2" v-on:input="changeIsAnnualized" />
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty screenshot-hide" v-show="trade.hideCommen"></div>
|
|
||||||
<div class="pitem-cash screenshot-hide"></div>
|
|
||||||
|
|
||||||
<div class="ptitle screenshot-hide">年化系数</div>
|
|
||||||
<div class="pitem screenshot-hide" v-show="!trade.hideCommen">
|
|
||||||
<div class="row no-gutters" v-if="trade.IsAnnualized2">
|
|
||||||
<div class="col">
|
|
||||||
<vue-number-input name="AnnualizeFactor2" v-model="AnnualizeFactor2.ttmDays" v-bind:format="inputFormatDouble2" v-on:input="changeAnnualizeFactor" class="text-right pr-2"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="col-auto" style="width:1rem">/</div>
|
|
||||||
<div class="col">
|
|
||||||
<vue-number-input name="AnnualizeFactor2" v-model="AnnualizeFactor2.daysInYear" v-bind:format="inputFormatDouble2" v-on:input="changeAnnualizeFactor" class="text-left pl-2"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty screenshot-hide" v-show="trade.hideCommen"></div>
|
|
||||||
<div class="pitem-cash screenshot-hide"></div>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<div class="ptitle screenshot-hide">是否年化</div>
|
|
||||||
<div class="pitem screenshot-hide" v-show="!trade.hideCommen">
|
|
||||||
<vue-niceselect name="IsAnnualized" :items="consFalseAsNo" v-model="trade.IsAnnualized" v-on:input="changeIsAnnualized" />
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty screenshot-hide" v-show="trade.hideCommen"></div>
|
|
||||||
<div class="pitem-cash screenshot-hide"></div>
|
|
||||||
|
|
||||||
<div class="ptitle screenshot-hide">年化系数</div>
|
|
||||||
<div class="pitem screenshot-hide" v-show="!trade.hideCommen">
|
|
||||||
<div class="row no-gutters" v-if="trade.IsAnnualized">
|
|
||||||
<div class="col">
|
|
||||||
<vue-number-input v-model="AnnualizeFactor.ttmDays" v-bind:format="inputFormatDouble2" v-on:input="changeAnnualizeFactor" class="text-right pr-2"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
<div class="col-auto" style="width:1rem">/</div>
|
|
||||||
<div class="col">
|
|
||||||
<vue-number-input v-model="AnnualizeFactor.daysInYear" v-bind:format="inputFormatDouble2" v-on:input="changeAnnualizeFactor" class="text-left pl-2"></vue-number-input>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty screenshot-hide" v-show="trade.hideCommen"></div>
|
|
||||||
<div class="pitem-cash screenshot-hide"></div>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!--定价模型-->
|
|
||||||
<template v-if="!topVue.simpleMode">
|
|
||||||
<div class="ptitle screenshot-hide">定价模型</div>
|
|
||||||
<div class="pitem screenshot-hide" v-show="!trade.hideCommen">
|
|
||||||
<vue-niceselect name="EngineName" :items="engineNames" v-model="trade.EngineName" :disabled="!canEditEngineName" />
|
|
||||||
</div>
|
|
||||||
<div class="pitem empty screenshot-hide" v-show="trade.hideCommen"></div>
|
|
||||||
<div class="pitem-cash screenshot-hide"></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<!--单笔计算结果-->
|
|
||||||
<div class="ptitle screenshot-hide" style="height:130px;background: #fff;border:0;">
|
|
||||||
<div class="ptitle-calc-result" style="border-bottom:1px solid #ddd;">单笔计算结果</div>
|
|
||||||
<div style="height: 54px;" v-show="!floating">
|
|
||||||
<div>
|
|
||||||
<button type="button" class="btn btn-primary mt-3" onclick="pricingVue.calcPrice()">定价计算</button>
|
|
||||||
</div>
|
|
||||||
<div v-show="!topVue.simpleMode">
|
|
||||||
<button type="button" class="btn btn-primary mt-3" onclick="pricingVue.combine()">自由组合</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="pitem pitem-cash border-0 screenshot-hide" style="height:130px">
|
|
||||||
<table class="table table-bordered table-calc-result-1">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th style="width:50%">PV</th>
|
|
||||||
<th style="width:50%" title="每报价单位Delta*手数">Delta</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td style="width:50%">{{calcResult.Pv}}</td>
|
|
||||||
<td style="width:50%">{{calcResult.Delta}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th title="每报价单位GammaCash*手数">GammaCash</th>
|
|
||||||
<th title="每报价单位Vega*交易份额">Vega</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{{calcResult.GammaCash}}</td>
|
|
||||||
<td>{{calcResult.Vega}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th title="每报价单位Theta*交易份额">Theta</th>
|
|
||||||
<th title="每报价单位Rho*交易份额*100">Rho</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>{{calcResult.Theta}}</td>
|
|
||||||
<td>{{calcResult.Rho}}</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="pitem screenshot-fill"></div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
<form id="marginTemplateV2Form" method="post" onsubmit="return false;">
|
<form id="marginTemplateV2Form" method="post" onsubmit="return false;">
|
||||||
<div class="row no-gutters">
|
<div class="row no-gutters">
|
||||||
<div class="col form-layout" style="height: 720px; overflow-y: auto;">
|
<div class="col form-layout tpl-base" style="height: calc(100vh - 120px); overflow-y: auto;">
|
||||||
<div class="border">
|
<div class="border">
|
||||||
<p>新模板信息</p>
|
<p>新模板信息</p>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -142,7 +142,7 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="formlabel">规则描述</label>
|
<label class="formlabel">规则描述</label>
|
||||||
<textarea class="text-box" rows="3" style="width: 320px; text-align:left;" v-model="marginTemplate.Comments" v-bind:title="marginTemplate.Comments" disabled>
|
<textarea class="text-box" rows="3" style="text-align:left;" v-model="marginTemplate.Comments" v-bind:title="marginTemplate.Comments" disabled>
|
||||||
</textarea>
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -158,7 +158,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="formlabel"></label>
|
<label class="formlabel"></label>
|
||||||
<textarea class="text-box" rows="5" style="width: 460px; text-align:left;" v-model="marginTemplate.UnderlyingSeperateComments" v-bind:title="marginTemplate.UnderlyingSeperateComments" disabled>
|
<textarea class="text-box" rows="5" style="text-align:left;" v-model="marginTemplate.UnderlyingSeperateComments" v-bind:title="marginTemplate.UnderlyingSeperateComments" disabled>
|
||||||
</textarea>
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -167,15 +167,15 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col form-layout" style="height: 720px; overflow-y:auto;">
|
<div class="col form-layout" style="height: calc(100vh - 120px); overflow-y:auto;">
|
||||||
<template v-if="marginTemplate.RuleType == @((int)MarginRuleTypeEnum.区间追保结构)">
|
<template v-if="marginTemplate.RuleType == @((int)MarginRuleTypeEnum.区间追保结构)">
|
||||||
<div class="border detail">
|
<div class="border detail">
|
||||||
<table class="table table-bordered" style="margin-bottom:0;">
|
<table class="table table-bordered" style="margin-bottom:0;">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th v-if="marginTemplate.UnderlyingSeperateType == @((int)UnderlyingSeperateTypeEnum.CustomInstrumentType)">标的资产类型</th>
|
<th v-if="marginTemplate.UnderlyingSeperateType == @((int)UnderlyingSeperateTypeEnum.CustomInstrumentType)">标的资产类型</th>
|
||||||
<th style="width:120px;">期限档位</th>
|
<th style="width:220px;">期限档位</th>
|
||||||
<th style="width:80px;">操作</th>
|
<th style="width:110px;">操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -214,7 +214,7 @@
|
|||||||
</td>
|
</td>
|
||||||
@*期限档由区块结构固定承载(纯利率债区块固定4档、其他区块为空=全部),只读展示不再下拉选择*@
|
@*期限档由区块结构固定承载(纯利率债区块固定4档、其他区块为空=全部),只读展示不再下拉选择*@
|
||||||
<td>{{bondTermLabel(row.detail)}}</td>
|
<td>{{bondTermLabel(row.detail)}}</td>
|
||||||
<td v-if="row.rowspan > 0" v-bind:rowspan="row.rowspan" style="vertical-align:middle;"><button class="delBtn" type="button" v-on:click="deleteDetail(row.index)">- 刪除区块</button></td>
|
<td v-if="row.rowspan > 0" v-bind:rowspan="row.rowspan" style="vertical-align:middle;"><button class="delBtn" type="button" v-on:click="deleteDetail(row.index)">- 删除区块</button></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -225,10 +225,10 @@
|
|||||||
参数组{{blk.no}}:<span v-if="marginTemplate.UnderlyingSeperateType == @((int)UnderlyingSeperateTypeEnum.CustomInstrumentType)">资产类型:{{underlyingTypeNames(blk.ut)}}</span>
|
参数组{{blk.no}}:<span v-if="marginTemplate.UnderlyingSeperateType == @((int)UnderlyingSeperateTypeEnum.CustomInstrumentType)">资产类型:{{underlyingTypeNames(blk.ut)}}</span>
|
||||||
@*ETF 子类(仅纯基金区块展示):选 可转债ETF/科创债ETF 分期限档(展开4档),其他子类/不区分不分档*@
|
@*ETF 子类(仅纯基金区块展示):选 可转债ETF/科创债ETF 分期限档(展开4档),其他子类/不区分不分档*@
|
||||||
<span v-if="blk.isFundBlock"> ETF 子类:<select v-model="blk.sections[0].detail.SpanConfig.EtfKind" v-on:change="onEtfKindChange(blk)"><option value="">不区分</option><option v-for="it in etfSubtypeItems" v-bind:value="it">{{it}}</option></select></span>
|
<span v-if="blk.isFundBlock"> ETF 子类:<select v-model="blk.sections[0].detail.SpanConfig.EtfKind" v-on:change="onEtfKindChange(blk)"><option value="">不区分</option><option v-for="it in etfSubtypeItems" v-bind:value="it">{{it}}</option></select></span>
|
||||||
<span v-if="blk.isTBond || blk.isTieredEtf">(按期限分档:≤5y、(5y-10y]、(10y-30y]、>30y,每个档位独立设置)</span>
|
<span v-if="blk.isTBond">(按期限分档:≤5y、(5y-10y]、(10y-30y]、>30y,每个档位独立设置)</span>
|
||||||
</p>
|
</p>
|
||||||
<div v-for="sec in blk.sections" v-bind:key="sec.key">
|
<div v-for="sec in blk.sections" v-bind:key="sec.key">
|
||||||
<p v-if="blk.isTBond || blk.isTieredEtf" style="margin:8px 0 2px; font-weight:bold;">期限档位:{{sec.termLabel}}</p>
|
<p v-if="blk.isTBond" style="margin:8px 0 2px; font-weight:bold;">期限档位:{{sec.termLabel}}</p>
|
||||||
<template v-if="sec.detail && sec.detail.SpanConfig">
|
<template v-if="sec.detail && sec.detail.SpanConfig">
|
||||||
<p style="margin:4px 0;">
|
<p style="margin:4px 0;">
|
||||||
预警线:<vue-number-input v-model="sec.detail.SpanConfig.WarnLine" v-bind:format="inputFormatPercent"></vue-number-input>
|
预警线:<vue-number-input v-model="sec.detail.SpanConfig.WarnLine" v-bind:format="inputFormatPercent"></vue-number-input>
|
||||||
@@ -507,7 +507,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto" v-show="index + 1 == marginTemplate.Details.length">
|
<div class="col-auto" v-show="index + 1 == marginTemplate.Details.length">
|
||||||
<button class="delBtn" v-show="marginTemplate.UnderlyingSeperateType == @((int)UnderlyingSeperateTypeEnum.CustomStock) || marginTemplate.UnderlyingSeperateType == @((int)UnderlyingSeperateTypeEnum.CustomInstrumentType) || marginTemplate.RuleType == @((int)MarginRuleTypeEnum.区间追保结构)" v-on:click="deleteDetail(index)">- 刪除</button>
|
<button class="delBtn" v-show="marginTemplate.UnderlyingSeperateType == @((int)UnderlyingSeperateTypeEnum.CustomStock) || marginTemplate.UnderlyingSeperateType == @((int)UnderlyingSeperateTypeEnum.CustomInstrumentType) || marginTemplate.RuleType == @((int)MarginRuleTypeEnum.区间追保结构)" v-on:click="deleteDetail(index)">- 删除</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
<form id="marginTemplateV2Form" method="post" onsubmit="return false;">
|
<form id="marginTemplateV2Form" method="post" onsubmit="return false;">
|
||||||
<div class="row no-gutters">
|
<div class="row no-gutters">
|
||||||
<div class="col form-layout" style="height: 720px; overflow-y: auto;">
|
<div class="col form-layout tpl-base" style="height: calc(100vh - 120px); overflow-y: auto;">
|
||||||
<div class="border">
|
<div class="border">
|
||||||
<P>新模板信息</P>
|
<P>新模板信息</P>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -149,7 +149,7 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="formlabel">规则描述</label>
|
<label class="formlabel">规则描述</label>
|
||||||
<textarea class="text-box" rows="3" style="width: 460px; text-align:left;" v-model="marginTemplate.Comments" v-bind:title="marginTemplate.Comments" disabled>
|
<textarea class="text-box" rows="3" style="text-align:left;" v-model="marginTemplate.Comments" v-bind:title="marginTemplate.Comments" disabled>
|
||||||
</textarea>
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -163,20 +163,20 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="formlabel"></label>
|
<label class="formlabel"></label>
|
||||||
<textarea class="text-box" rows="5" style="width: 460px; text-align:left;" v-model="marginTemplate.UnderlyingSeperateComments" v-bind:title="marginTemplate.UnderlyingSeperateComments" disabled>
|
<textarea class="text-box" rows="5" style="text-align:left;" v-model="marginTemplate.UnderlyingSeperateComments" v-bind:title="marginTemplate.UnderlyingSeperateComments" disabled>
|
||||||
</textarea>
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col form-layout" style="height: 720px; overflow-y:auto;">
|
<div class="col form-layout" style="height: calc(100vh - 120px); overflow-y:auto;">
|
||||||
<template v-if="marginTemplate.RuleType == @((int)MarginRuleTypeEnum.区间追保结构)">
|
<template v-if="marginTemplate.RuleType == @((int)MarginRuleTypeEnum.区间追保结构)">
|
||||||
<div class="border detail">
|
<div class="border detail">
|
||||||
<table class="table table-bordered" style="margin-bottom:0;">
|
<table class="table table-bordered" style="margin-bottom:0;">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th v-if="marginTemplate.UnderlyingSeperateType == @((int)UnderlyingSeperateTypeEnum.CustomInstrumentType)">标的资产类型</th>
|
<th v-if="marginTemplate.UnderlyingSeperateType == @((int)UnderlyingSeperateTypeEnum.CustomInstrumentType)">标的资产类型</th>
|
||||||
<th style="width:120px;">期限档位</th>
|
<th style="width:220px;">期限档位</th>
|
||||||
<th style="width:80px;">操作</th>
|
<th style="width:110px;">操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -215,7 +215,7 @@
|
|||||||
</td>
|
</td>
|
||||||
@*期限档由区块结构固定承载(纯利率债区块固定4档、其他区块为空=全部),只读展示不再下拉选择*@
|
@*期限档由区块结构固定承载(纯利率债区块固定4档、其他区块为空=全部),只读展示不再下拉选择*@
|
||||||
<td>{{bondTermLabel(row.detail)}}</td>
|
<td>{{bondTermLabel(row.detail)}}</td>
|
||||||
<td v-if="row.rowspan > 0" v-bind:rowspan="row.rowspan" style="vertical-align:middle;"><button class="delBtn" type="button" v-on:click="deleteDetail(row.index)">- 刪除区块</button></td>
|
<td v-if="row.rowspan > 0" v-bind:rowspan="row.rowspan" style="vertical-align:middle;"><button class="delBtn" type="button" v-on:click="deleteDetail(row.index)">- 删除区块</button></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -226,10 +226,10 @@
|
|||||||
参数组{{blk.no}}:<span v-if="marginTemplate.UnderlyingSeperateType == @((int)UnderlyingSeperateTypeEnum.CustomInstrumentType)">资产类型:{{underlyingTypeNames(blk.ut)}}</span>
|
参数组{{blk.no}}:<span v-if="marginTemplate.UnderlyingSeperateType == @((int)UnderlyingSeperateTypeEnum.CustomInstrumentType)">资产类型:{{underlyingTypeNames(blk.ut)}}</span>
|
||||||
@*ETF 子类(仅纯基金区块展示):选 可转债ETF/科创债ETF 分期限档(展开4档),其他子类/不区分不分档*@
|
@*ETF 子类(仅纯基金区块展示):选 可转债ETF/科创债ETF 分期限档(展开4档),其他子类/不区分不分档*@
|
||||||
<span v-if="blk.isFundBlock"> ETF 子类:<select v-model="blk.sections[0].detail.SpanConfig.EtfKind" v-on:change="onEtfKindChange(blk)"><option value="">不区分</option><option v-for="it in etfSubtypeItems" v-bind:value="it">{{it}}</option></select></span>
|
<span v-if="blk.isFundBlock"> ETF 子类:<select v-model="blk.sections[0].detail.SpanConfig.EtfKind" v-on:change="onEtfKindChange(blk)"><option value="">不区分</option><option v-for="it in etfSubtypeItems" v-bind:value="it">{{it}}</option></select></span>
|
||||||
<span v-if="blk.isTBond || blk.isTieredEtf">(按期限分档:≤5y、(5y-10y]、(10y-30y]、>30y,每个档位独立设置)</span>
|
<span v-if="blk.isTBond">(按期限分档:≤5y、(5y-10y]、(10y-30y]、>30y,每个档位独立设置)</span>
|
||||||
</p>
|
</p>
|
||||||
<div v-for="sec in blk.sections" v-bind:key="sec.key">
|
<div v-for="sec in blk.sections" v-bind:key="sec.key">
|
||||||
<p v-if="blk.isTBond || blk.isTieredEtf" style="margin:8px 0 2px; font-weight:bold;">期限档位:{{sec.termLabel}}</p>
|
<p v-if="blk.isTBond" style="margin:8px 0 2px; font-weight:bold;">期限档位:{{sec.termLabel}}</p>
|
||||||
<template v-if="sec.detail && sec.detail.SpanConfig">
|
<template v-if="sec.detail && sec.detail.SpanConfig">
|
||||||
<p style="margin:4px 0;">
|
<p style="margin:4px 0;">
|
||||||
预警线:<vue-number-input v-model="sec.detail.SpanConfig.WarnLine" v-bind:format="inputFormatPercent"></vue-number-input>
|
预警线:<vue-number-input v-model="sec.detail.SpanConfig.WarnLine" v-bind:format="inputFormatPercent"></vue-number-input>
|
||||||
@@ -487,7 +487,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto" v-show="index + 1 == marginTemplate.Details.length">
|
<div class="col-auto" v-show="index + 1 == marginTemplate.Details.length">
|
||||||
<button class="delBtn" v-show="marginTemplate.UnderlyingSeperateType == @((int)UnderlyingSeperateTypeEnum.CustomStock) || marginTemplate.UnderlyingSeperateType == @((int)UnderlyingSeperateTypeEnum.CustomInstrumentType) || marginTemplate.RuleType == @((int)MarginRuleTypeEnum.区间追保结构)" v-on:click="deleteDetail(index)">- 刪除</button>
|
<button class="delBtn" v-show="marginTemplate.UnderlyingSeperateType == @((int)UnderlyingSeperateTypeEnum.CustomStock) || marginTemplate.UnderlyingSeperateType == @((int)UnderlyingSeperateTypeEnum.CustomInstrumentType) || marginTemplate.RuleType == @((int)MarginRuleTypeEnum.区间追保结构)" v-on:click="deleteDetail(index)">- 删除</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
<form id="marginTemplateV2Form" method="post" onsubmit="return false;">
|
<form id="marginTemplateV2Form" method="post" onsubmit="return false;">
|
||||||
<div class="row no-gutters">
|
<div class="row no-gutters">
|
||||||
<div class="col form-layout" style="height: calc(100vh - 120px); overflow-y: auto;">
|
<div class="col form-layout tpl-base" style="height: calc(100vh - 120px); overflow-y: auto;">
|
||||||
<div class="border">
|
<div class="border">
|
||||||
<P>新模板信息</P>
|
<P>新模板信息</P>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -115,7 +115,7 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="formlabel">规则描述</label>
|
<label class="formlabel">规则描述</label>
|
||||||
<textarea class="text-box" rows="3" style="width: 320px; text-align:left;" v-model="marginTemplate.Comments" v-bind:title="marginTemplate.Comments" disabled>
|
<textarea class="text-box" rows="3" style="text-align:left;" v-model="marginTemplate.Comments" v-bind:title="marginTemplate.Comments" disabled>
|
||||||
</textarea>
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="formlabel"></label>
|
<label class="formlabel"></label>
|
||||||
<textarea class="text-box" rows="5" style="width: 320px; text-align:left;" v-model="marginTemplate.UnderlyingSeperateComments" v-bind:title="marginTemplate.UnderlyingSeperateComments" disabled>
|
<textarea class="text-box" rows="5" style="text-align:left;" v-model="marginTemplate.UnderlyingSeperateComments" v-bind:title="marginTemplate.UnderlyingSeperateComments" disabled>
|
||||||
</textarea>
|
</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -140,8 +140,8 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th v-if="marginTemplate.UnderlyingSeperateType == @((int)UnderlyingSeperateTypeEnum.CustomInstrumentType)">标的资产类型</th>
|
<th v-if="marginTemplate.UnderlyingSeperateType == @((int)UnderlyingSeperateTypeEnum.CustomInstrumentType)">标的资产类型</th>
|
||||||
<th style="width:120px;">期限档位</th>
|
<th style="width:220px;">期限档位</th>
|
||||||
<th style="width:80px;">操作</th>
|
<th style="width:110px;">操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -180,7 +180,7 @@
|
|||||||
</td>
|
</td>
|
||||||
@*期限档由区块结构固定承载(纯利率债区块固定4档、其他区块为空=全部),只读展示不再下拉选择*@
|
@*期限档由区块结构固定承载(纯利率债区块固定4档、其他区块为空=全部),只读展示不再下拉选择*@
|
||||||
<td>{{bondTermLabel(row.detail)}}</td>
|
<td>{{bondTermLabel(row.detail)}}</td>
|
||||||
<td v-if="row.rowspan > 0" v-bind:rowspan="row.rowspan" style="vertical-align:middle;"><button class="delBtn" type="button" v-on:click="deleteDetail(row.index)">- 刪除区块</button></td>
|
<td v-if="row.rowspan > 0" v-bind:rowspan="row.rowspan" style="vertical-align:middle;"><button class="delBtn" type="button" v-on:click="deleteDetail(row.index)">- 删除区块</button></td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@@ -191,10 +191,10 @@
|
|||||||
参数组{{blk.no}}:<span v-if="marginTemplate.UnderlyingSeperateType == @((int)UnderlyingSeperateTypeEnum.CustomInstrumentType)">资产类型:{{underlyingTypeNames(blk.ut)}}</span>
|
参数组{{blk.no}}:<span v-if="marginTemplate.UnderlyingSeperateType == @((int)UnderlyingSeperateTypeEnum.CustomInstrumentType)">资产类型:{{underlyingTypeNames(blk.ut)}}</span>
|
||||||
@*ETF 子类(仅纯基金区块展示):选 可转债ETF/科创债ETF 分期限档(展开4档),其他子类/不区分不分档*@
|
@*ETF 子类(仅纯基金区块展示):选 可转债ETF/科创债ETF 分期限档(展开4档),其他子类/不区分不分档*@
|
||||||
<span v-if="blk.isFundBlock"> ETF 子类:<select v-model="blk.sections[0].detail.SpanConfig.EtfKind" v-on:change="onEtfKindChange(blk)"><option value="">不区分</option><option v-for="it in etfSubtypeItems" v-bind:value="it">{{it}}</option></select></span>
|
<span v-if="blk.isFundBlock"> ETF 子类:<select v-model="blk.sections[0].detail.SpanConfig.EtfKind" v-on:change="onEtfKindChange(blk)"><option value="">不区分</option><option v-for="it in etfSubtypeItems" v-bind:value="it">{{it}}</option></select></span>
|
||||||
<span v-if="blk.isTBond || blk.isTieredEtf">(按期限分档:≤5y、(5y-10y]、(10y-30y]、>30y,每个档位独立设置)</span>
|
<span v-if="blk.isTBond">(按期限分档:≤5y、(5y-10y]、(10y-30y]、>30y,每个档位独立设置)</span>
|
||||||
</p>
|
</p>
|
||||||
<div v-for="sec in blk.sections" v-bind:key="sec.key">
|
<div v-for="sec in blk.sections" v-bind:key="sec.key">
|
||||||
<p v-if="blk.isTBond || blk.isTieredEtf" style="margin:8px 0 2px; font-weight:bold;">期限档位:{{sec.termLabel}}</p>
|
<p v-if="blk.isTBond" style="margin:8px 0 2px; font-weight:bold;">期限档位:{{sec.termLabel}}</p>
|
||||||
<template v-if="sec.detail && sec.detail.SpanConfig">
|
<template v-if="sec.detail && sec.detail.SpanConfig">
|
||||||
<p style="margin:4px 0;">
|
<p style="margin:4px 0;">
|
||||||
预警线:<vue-number-input v-model="sec.detail.SpanConfig.WarnLine" v-bind:format="inputFormatPercent"></vue-number-input>
|
预警线:<vue-number-input v-model="sec.detail.SpanConfig.WarnLine" v-bind:format="inputFormatPercent"></vue-number-input>
|
||||||
|
|||||||
@@ -93,14 +93,7 @@
|
|||||||
<script src="~/Scripts/app/tradeHelper.js?v=@HtmlUtil.JsVersion"></script>
|
<script src="~/Scripts/app/tradeHelper.js?v=@HtmlUtil.JsVersion"></script>
|
||||||
<script src="~/Scripts/app/trade/percentColumnText.js?v=@HtmlUtil.JsVersion"></script>
|
<script src="~/Scripts/app/trade/percentColumnText.js?v=@HtmlUtil.JsVersion"></script>
|
||||||
|
|
||||||
@if (PS.Config.Is润和)
|
<script src="~/Scripts/app/pricing/tradePricing.js?v=@HtmlUtil.JsVersion"></script>
|
||||||
{
|
|
||||||
<script src="~/Scripts/app/pricing/tradePricing_dz.js?v=@HtmlUtil.JsVersion"></script>
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<script src="~/Scripts/app/pricing/tradePricing.js?v=@HtmlUtil.JsVersion"></script>
|
|
||||||
}
|
|
||||||
<script src="~/Scripts/app/trade/tradeEditV2.js?v=@HtmlUtil.JsVersion"></script>
|
<script src="~/Scripts/app/trade/tradeEditV2.js?v=@HtmlUtil.JsVersion"></script>
|
||||||
|
|
||||||
<script src="~/Scripts/app/trade/settag.js?v=@HtmlUtil.JsVersion" type="text/javascript"></script>
|
<script src="~/Scripts/app/trade/settag.js?v=@HtmlUtil.JsVersion" type="text/javascript"></script>
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
$(function () {
|
|
||||||
var autoClientCtrl = FastVue.autocomplete(document.getElementById('ClientId'), {
|
|
||||||
lookup: ylotc.clients, nameField: 'Name', valueField: 'id', searchField: ['Name', 'Code', 'PinYin'],
|
|
||||||
onSelect: function (data) {
|
|
||||||
console.log(data);
|
|
||||||
console.log('#ClientId Value:' + $('#ClientId').val());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -47,10 +47,6 @@ const TermTierEnabledUnderlyingMask = 16;
|
|||||||
//基金及基金专户标志位(ETF 子类行的 UnderlyingType,不加新枚举位)
|
//基金及基金专户标志位(ETF 子类行的 UnderlyingType,不加新枚举位)
|
||||||
const FundTypeMask = 32768;
|
const FundTypeMask = 32768;
|
||||||
|
|
||||||
//允许配置期限档的 ETF 子类(SpanConfig.EtfKind 值,取值=数据字典"ETF 子类"),
|
|
||||||
//与后端 ConsMarginTerm.TermTierEnabledEtfKinds 保持一致;其余子类与"不区分"的基金行不分档
|
|
||||||
const TermTierEnabledEtfKinds = ['可转债 ETF', '科创债 ETF'];
|
|
||||||
|
|
||||||
//利率债区块固定展开的4个期限档([BondTerm值, 展示文案]),与 docx 原型 4.3.1 一致
|
//利率债区块固定展开的4个期限档([BondTerm值, 展示文案]),与 docx 原型 4.3.1 一致
|
||||||
const SpanBondTerms = [['<5y', '≤5y'], ['5y-10y', '(5y-10y]'], ['10y-30y', '(10y-30y]'], ['>30y', '>30y']];
|
const SpanBondTerms = [['<5y', '≤5y'], ['5y-10y', '(5y-10y]'], ['10y-30y', '(10y-30y]'], ['>30y', '>30y']];
|
||||||
|
|
||||||
@@ -74,6 +70,10 @@ const vue = new Vue({
|
|||||||
etfSubtypeItems: page.etfSubtypeItems || []
|
etfSubtypeItems: page.etfSubtypeItems || []
|
||||||
},
|
},
|
||||||
created: function () {
|
created: function () {
|
||||||
|
//留档进入页面时的生效状态:v-model 改写的就是 page.marginTemplate 同一对象(data 浅拷贝的是引用),
|
||||||
|
//原始值须在用户交互前记下,供保存时判断"生效中规则被改为否"弹失效确认;
|
||||||
|
//select 的 v-model 取值是字符串,统一 String 化比较
|
||||||
|
this.originalIsValid = String(this.marginTemplate.IsValid);
|
||||||
//区间追保结构:加载时按 资产类型+期限 排序一次,再重建资产类型区块(利率债区块补齐固定4档),
|
//区间追保结构:加载时按 资产类型+期限 排序一次,再重建资产类型区块(利率债区块补齐固定4档),
|
||||||
//编辑过程中不再重排,避免 chosen/选择器失序
|
//编辑过程中不再重排,避免 chosen/选择器失序
|
||||||
if (this.marginTemplate.RuleType == MarginRuleTypeEnum.区间追保结构 && this.marginTemplate.Details) {
|
if (this.marginTemplate.RuleType == MarginRuleTypeEnum.区间追保结构 && this.marginTemplate.Details) {
|
||||||
@@ -118,8 +118,8 @@ const vue = new Vue({
|
|||||||
}
|
}
|
||||||
return rows;
|
return rows;
|
||||||
},
|
},
|
||||||
//区间追保结构录入区块:每个资产类型区块一个;纯利率债(ut=16)与分档 ETF 子类
|
//区间追保结构录入区块:每个资产类型区块一个;纯利率债(ut=16)区块固定展开4个期限档段(每段一条 detail),
|
||||||
//(ut=基金 + EtfKind∈可转债/科创债 ETF)区块固定展开4个期限档段(每段一条 detail),其他区块单段(BondTerm 为空)。
|
//其他区块(含全部 ETF 子类,2026-08-27 裁定 ETF 无期限概念不再分档)单段(BondTerm 为空)。
|
||||||
//段的 detail 缺失时模板侧 v-if 兜底不渲染该段
|
//段的 detail 缺失时模板侧 v-if 兜底不渲染该段
|
||||||
ruleRangeBlocks() {
|
ruleRangeBlocks() {
|
||||||
if (this.marginTemplate.RuleType != MarginRuleTypeEnum.区间追保结构) return [];
|
if (this.marginTemplate.RuleType != MarginRuleTypeEnum.区间追保结构) return [];
|
||||||
@@ -132,10 +132,8 @@ const vue = new Vue({
|
|||||||
var ut = head.detail.UnderlyingType || 0;
|
var ut = head.detail.UnderlyingType || 0;
|
||||||
var kind = (head.detail.SpanConfig && head.detail.SpanConfig.EtfKind) || '';
|
var kind = (head.detail.SpanConfig && head.detail.SpanConfig.EtfKind) || '';
|
||||||
var isTBond = ut === 16;
|
var isTBond = ut === 16;
|
||||||
var isTieredEtf = ut === FundTypeMask && TermTierEnabledEtfKinds.indexOf(kind) >= 0;
|
|
||||||
var isTiered = isTBond || isTieredEtf;
|
|
||||||
var sections = [];
|
var sections = [];
|
||||||
if (isTiered) {
|
if (isTBond) {
|
||||||
for (var t = 0; t < SpanBondTerms.length; t++) {
|
for (var t = 0; t < SpanBondTerms.length; t++) {
|
||||||
var found = null;
|
var found = null;
|
||||||
for (var j = head.index; j < head.index + head.rowspan; j++) {
|
for (var j = head.index; j < head.index + head.rowspan; j++) {
|
||||||
@@ -147,7 +145,7 @@ const vue = new Vue({
|
|||||||
} else {
|
} else {
|
||||||
sections.push({ key: 'single', termLabel: '', detail: head.detail });
|
sections.push({ key: 'single', termLabel: '', detail: head.detail });
|
||||||
}
|
}
|
||||||
blocks.push({ key: head.detail._bk || ('i' + head.index), no: blocks.length + 1, headIndex: head.index, ut: ut, etfKind: kind, isTBond: isTBond, isTieredEtf: isTieredEtf, isFundBlock: ut === FundTypeMask, sections: sections });
|
blocks.push({ key: head.detail._bk || ('i' + head.index), no: blocks.length + 1, headIndex: head.index, ut: ut, etfKind: kind, isTBond: isTBond, isFundBlock: ut === FundTypeMask, sections: sections });
|
||||||
}
|
}
|
||||||
return blocks;
|
return blocks;
|
||||||
}
|
}
|
||||||
@@ -268,6 +266,18 @@ const vue = new Vue({
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
saveMarginTemplateV2(isForClient) {
|
saveMarginTemplateV2(isForClient) {
|
||||||
|
//失效确认:编辑中把"生效中"规则改为否时先弹窗提示降级影响,确认后才真正提交;
|
||||||
|
//新增规则尚未生效、生效状态未翻转,不弹。自定义规则编辑页无"是否生效"开关,不经过此逻辑
|
||||||
|
if (!this.isAdd && this.originalIsValid === 'true' && String(this.marginTemplate.IsValid) === 'false') {
|
||||||
|
var that = this;
|
||||||
|
main.confirm("该规则失效后,适用范围内的持仓将降级匹配下一优先级规则(客户→全局),确认继续?", function () {
|
||||||
|
that.doSaveMarginTemplateV2(isForClient);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.doSaveMarginTemplateV2(isForClient);
|
||||||
|
},
|
||||||
|
doSaveMarginTemplateV2(isForClient) {
|
||||||
if (!this.marginTemplate.Name) {
|
if (!this.marginTemplate.Name) {
|
||||||
main.message("模板名称不能为空");
|
main.message("模板名称不能为空");
|
||||||
return;
|
return;
|
||||||
@@ -434,64 +444,35 @@ const vue = new Vue({
|
|||||||
d.SpanConfig.EtfKind = etfKind || null;
|
d.SpanConfig.EtfKind = etfKind || null;
|
||||||
return d;
|
return d;
|
||||||
},
|
},
|
||||||
//ETF 子类选择器变更(仅纯基金区块渲染):选可转债/科创债 ETF → 区块展开固定4档(缺档补行、异常档行删除);
|
//ETF 子类选择器变更(仅纯基金区块渲染):子类仅用于行区分(取数侧子类行优先),
|
||||||
//选其他子类/不区分 → 收敛为单行(BondTerm 置空,多余档位行删除,首行承载 EtfKind)
|
//ETF 无期限概念不分档——任何子类切换后区块始终收敛为单行(BondTerm 置空,多余档位行删除,首行承载 EtfKind;
|
||||||
|
//存量 4 档子类数据在这里被收敛时仅保留首行录入内容)
|
||||||
onEtfKindChange(blk) {
|
onEtfKindChange(blk) {
|
||||||
var head = blk.sections[0].detail;
|
var head = blk.sections[0].detail;
|
||||||
var kind = (head.SpanConfig && head.SpanConfig.EtfKind) || '';
|
var kind = (head.SpanConfig && head.SpanConfig.EtfKind) || '';
|
||||||
var tiered = TermTierEnabledEtfKinds.indexOf(kind) >= 0;
|
|
||||||
var details = this.marginTemplate.Details;
|
var details = this.marginTemplate.Details;
|
||||||
var bk = head._bk;
|
var bk = head._bk;
|
||||||
var rows = details.filter(function (d) { return d._bk === bk; });
|
var rows = details.filter(function (d) { return d._bk === bk; });
|
||||||
if (tiered) {
|
rows.forEach(function (r) {
|
||||||
var byTerm = {};
|
if (r !== head) {
|
||||||
rows.forEach(function (r) {
|
|
||||||
var bt = (r.SpanConfig && r.SpanConfig.BondTerm) || '';
|
|
||||||
if (byTerm[bt] === undefined) byTerm[bt] = r;
|
|
||||||
});
|
|
||||||
var that = this;
|
|
||||||
var merged = [];
|
|
||||||
//首行未被4个合法档位命中时(单段行 BondTerm 为空)复用为首个档位行,保留已录入内容;
|
|
||||||
//否则首行会以"EtfKind 已选、BondTerm 为空"的残留行留在明细里,保存时被服务端"分期限档类型必须配置期限档"拦截
|
|
||||||
var headMatched = SpanBondTerms.some(function (t) { return byTerm[t[0]] === head; });
|
|
||||||
SpanBondTerms.forEach(function (t, ti) {
|
|
||||||
var r = byTerm[t[0]] || (ti === 0 && !headMatched ? head : null);
|
|
||||||
if (!r) r = that.newSpanDetail(FundTypeMask, t[0], kind);
|
|
||||||
r.UnderlyingType = FundTypeMask;
|
|
||||||
r.SpanConfig.EtfKind = kind;
|
|
||||||
r.SpanConfig.BondTerm = t[0];
|
|
||||||
Vue.set(r, '_bk', bk);
|
|
||||||
merged.push(r);
|
|
||||||
var idx = details.indexOf(r);
|
var idx = details.indexOf(r);
|
||||||
if (idx >= 0 && r !== head) details.splice(idx, 1);
|
if (idx >= 0) details.splice(idx, 1);
|
||||||
});
|
}
|
||||||
//异常档/重复行全部移除后按档序回插到区块首行位置
|
});
|
||||||
var headIdx = details.indexOf(head);
|
head.UnderlyingType = FundTypeMask;
|
||||||
if (headIdx < 0) headIdx = details.length;
|
head.SpanConfig.BondTerm = '';
|
||||||
details.splice.apply(details, [headIdx + 1, 0].concat(merged.filter(function (r) { return r !== head; })));
|
head.SpanConfig.EtfKind = kind || null;
|
||||||
} else {
|
|
||||||
rows.forEach(function (r) {
|
|
||||||
if (r !== head) {
|
|
||||||
var idx = details.indexOf(r);
|
|
||||||
if (idx >= 0) details.splice(idx, 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
head.UnderlyingType = FundTypeMask;
|
|
||||||
head.SpanConfig.BondTerm = '';
|
|
||||||
head.SpanConfig.EtfKind = kind || null;
|
|
||||||
}
|
|
||||||
this.refreshChosen();
|
this.refreshChosen();
|
||||||
},
|
},
|
||||||
//分档行判定与分档键:纯利率债 → 'tbond';基金 + 分档 ETF 子类 → 'etf:子类'(同一子类的连续行归一个区块)
|
//分档行判定与分档键:纯利率债 → 'tbond'(连续行归一个区块按固定4档补齐);ETF 子类不分档,基金行一律独立成块
|
||||||
spanTierKey(d) {
|
spanTierKey(d) {
|
||||||
var ut = d.UnderlyingType || 0;
|
var ut = d.UnderlyingType || 0;
|
||||||
var kind = (d.SpanConfig && d.SpanConfig.EtfKind) || '';
|
|
||||||
if (ut === TermTierEnabledUnderlyingMask) return 'tbond';
|
if (ut === TermTierEnabledUnderlyingMask) return 'tbond';
|
||||||
if (ut === FundTypeMask && TermTierEnabledEtfKinds.indexOf(kind) >= 0) return 'etf:' + kind;
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
//存量回显重建资产类型区块(分配区块键 _bk):连续的纯利率债行、基金+分档ETF子类行各自归为区块并按固定4档补齐(缺档补空行);
|
//存量回显重建资产类型区块(分配区块键 _bk):连续的纯利率债行归为区块并按固定4档补齐(缺档补空行);
|
||||||
//同档重复/异常档的分档行、非分档行(含基金+不分档子类、基金通配行)均各自独立成块展示,不丢数据
|
//同档重复/异常档的分档行、其余全部行(含基金+子类行、基金通配行)均各自独立成块展示,不丢数据——
|
||||||
|
//存量 ETF 子类 4 档行会以多个单行区块出现,保存时由服务端"ETF 子类不分期限档"校验拦截提示清理
|
||||||
rebuildSpanBlocks(details) {
|
rebuildSpanBlocks(details) {
|
||||||
var termValues = SpanBondTerms.map(function (t) { return t[0]; });
|
var termValues = SpanBondTerms.map(function (t) { return t[0]; });
|
||||||
var result = [];
|
var result = [];
|
||||||
@@ -513,13 +494,10 @@ const vue = new Vue({
|
|||||||
if (termValues.indexOf(bt) >= 0 && !byTerm[bt]) byTerm[bt] = r; else anomalies.push(r);
|
if (termValues.indexOf(bt) >= 0 && !byTerm[bt]) byTerm[bt] = r; else anomalies.push(r);
|
||||||
});
|
});
|
||||||
var bk = 'bk_' + (++spanBlockSeq);
|
var bk = 'bk_' + (++spanBlockSeq);
|
||||||
var utv = tk === 'tbond' ? TermTierEnabledUnderlyingMask : FundTypeMask;
|
|
||||||
var kind = tk === 'tbond' ? '' : tk.substring(4);
|
|
||||||
termValues.forEach(function (t) {
|
termValues.forEach(function (t) {
|
||||||
var r = byTerm[t];
|
var r = byTerm[t];
|
||||||
if (!r) r = that.newSpanDetail(utv, t, kind);
|
if (!r) r = that.newSpanDetail(TermTierEnabledUnderlyingMask, t);
|
||||||
r.UnderlyingType = utv;
|
r.UnderlyingType = TermTierEnabledUnderlyingMask;
|
||||||
if (kind) r.SpanConfig.EtfKind = kind;
|
|
||||||
r.SpanConfig.BondTerm = t;
|
r.SpanConfig.BondTerm = t;
|
||||||
Vue.set(r, '_bk', bk);
|
Vue.set(r, '_bk', bk);
|
||||||
result.push(r);
|
result.push(r);
|
||||||
@@ -551,15 +529,19 @@ const vue = new Vue({
|
|||||||
return map[v] !== undefined ? map[v] : v;
|
return map[v] !== undefined ? map[v] : v;
|
||||||
},
|
},
|
||||||
//规则15录入区块文案:按 detail 资产类型切换计价口径。
|
//规则15录入区块文案:按 detail 资产类型切换计价口径。
|
||||||
//债券类(利率债16/信用债32/其它债券64)及其他类型(默认债券口径):期初净价/当前净价,金额=×期初全价×券面总额;
|
//比较价格口径与计算侧对齐(MarginCalculationBase.CalcSwapSpanMaintenanceMargin:IsBond→中债估值净价,其余→收盘价):
|
||||||
//基金及基金专户(32768)/债券指数(536870912):参考标的期初净价/参考标的当前收盘价(空头各层统一收盘价,BUG-11 修正),
|
//纯债券类(利率债16/信用债32/其它债券64,可组合):期初净价/当前净价,金额=×期初全价×券面总额;
|
||||||
|
//其余全部类型(基金/债券指数/股票/股指等):参考标的期初净价/参考标的当前收盘价(多空各层统一收盘价),
|
||||||
//金额=×参考标的期初价格×参考标的名义份额。
|
//金额=×参考标的期初价格×参考标的名义份额。
|
||||||
spanText(detail) {
|
spanText(detail) {
|
||||||
var ut = (detail && detail.UnderlyingType) || 0;
|
var ut = (detail && detail.UnderlyingType) || 0;
|
||||||
if ((ut & 32768) > 0 || (ut & 536870912) > 0) {
|
//非空且标志位全部落在债券三类内才按债券口径;混合行(债券|非债券)按收盘价口径显示,与取数侧标的实际类型判定方向一致
|
||||||
|
var bondMask = 16 | 32 | 64;
|
||||||
|
var isBond = ut !== 0 && (ut & ~bondMask) === 0;
|
||||||
|
if (!isBond) {
|
||||||
return {
|
return {
|
||||||
priceInit: '参考标的期初净价',
|
priceInit: '参考标的期初净价',
|
||||||
priceCur: '参考标的当前净价',
|
priceCur: '参考标的当前收盘价',
|
||||||
priceCurShort1: '参考标的当前收盘价',
|
priceCurShort1: '参考标的当前收盘价',
|
||||||
priceCurShort: '参考标的当前收盘价',
|
priceCurShort: '参考标的当前收盘价',
|
||||||
amountBase: '参考标的期初价格 × 参考标的名义份额'
|
amountBase: '参考标的期初价格 × 参考标的名义份额'
|
||||||
@@ -649,5 +631,23 @@ $(function () {
|
|||||||
if (!isNaN(idx)) vue.onUnderlyingTypeChange(idx);
|
if (!isNaN(idx)) vue.onUnderlyingTypeChange(idx);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//多选 chosen:已有选中项后隐藏搜索框——空框没有输入内容却占一行,放不下时还会换行留白
|
||||||
|
//(本页多选均为点选场景,无需键盘过滤);全部取消后恢复,显示"请选择…"占位。
|
||||||
|
//勾选变化会触发原 select 的 jQuery change(trigger_form_field_change),
|
||||||
|
//加载重建/增删区块后的 refreshChosen 会触发 chosen:updated,两处都走这里的委托统一刷新
|
||||||
|
function refreshChosenSearchField(select) {
|
||||||
|
var $sel = $(select);
|
||||||
|
var $container = $sel.next('.chosen-container-multi');
|
||||||
|
if ($container.length === 0) return;
|
||||||
|
var noneSelected = $sel.find('option:selected').length === 0;
|
||||||
|
$container.find('li.search-field').toggle(noneSelected);
|
||||||
|
}
|
||||||
|
$(document).on('change chosen:updated', 'select.chosen-select[multiple]', function () {
|
||||||
|
refreshChosenSearchField(this);
|
||||||
|
});
|
||||||
|
|
||||||
SetAceDropDown();
|
SetAceDropDown();
|
||||||
|
$('select.chosen-select[multiple]').each(function () {
|
||||||
|
refreshChosenSearchField(this);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -35,10 +35,6 @@ const TermTierEnabledUnderlyingMask = 16;
|
|||||||
//基金及基金专户标志位(ETF 子类行的 UnderlyingType,不加新枚举位)
|
//基金及基金专户标志位(ETF 子类行的 UnderlyingType,不加新枚举位)
|
||||||
const FundTypeMask = 32768;
|
const FundTypeMask = 32768;
|
||||||
|
|
||||||
//允许配置期限档的 ETF 子类(SpanConfig.EtfKind 值,取值=数据字典"ETF 子类"),
|
|
||||||
//与后端 ConsMarginTerm.TermTierEnabledEtfKinds 保持一致;其余子类与"不区分"的基金行不分档
|
|
||||||
const TermTierEnabledEtfKinds = ['可转债 ETF', '科创债 ETF'];
|
|
||||||
|
|
||||||
//利率债区块固定展开的4个期限档([BondTerm值, 展示文案]),与 docx 原型 4.3.1 一致
|
//利率债区块固定展开的4个期限档([BondTerm值, 展示文案]),与 docx 原型 4.3.1 一致
|
||||||
const SpanBondTerms = [['<5y', '≤5y'], ['5y-10y', '(5y-10y]'], ['10y-30y', '(10y-30y]'], ['>30y', '>30y']];
|
const SpanBondTerms = [['<5y', '≤5y'], ['5y-10y', '(5y-10y]'], ['10y-30y', '(10y-30y]'], ['>30y', '>30y']];
|
||||||
|
|
||||||
@@ -106,8 +102,8 @@ const vue = new Vue({
|
|||||||
}
|
}
|
||||||
return rows;
|
return rows;
|
||||||
},
|
},
|
||||||
//区间追保结构录入区块:每个资产类型区块一个;纯利率债(ut=16)与分档 ETF 子类
|
//区间追保结构录入区块:每个资产类型区块一个;纯利率债(ut=16)区块固定展开4个期限档段(每段一条 detail),
|
||||||
//(ut=基金 + EtfKind∈可转债/科创债 ETF)区块固定展开4个期限档段(每段一条 detail),其他区块单段(BondTerm 为空)。
|
//其他区块(含全部 ETF 子类,2026-08-27 裁定 ETF 无期限概念不再分档)单段(BondTerm 为空)。
|
||||||
//段的 detail 缺失时模板侧 v-if 兜底不渲染该段
|
//段的 detail 缺失时模板侧 v-if 兜底不渲染该段
|
||||||
ruleRangeBlocks() {
|
ruleRangeBlocks() {
|
||||||
if (this.marginTemplate.RuleType != MarginRuleTypeEnum.区间追保结构) return [];
|
if (this.marginTemplate.RuleType != MarginRuleTypeEnum.区间追保结构) return [];
|
||||||
@@ -120,10 +116,8 @@ const vue = new Vue({
|
|||||||
var ut = head.detail.UnderlyingType || 0;
|
var ut = head.detail.UnderlyingType || 0;
|
||||||
var kind = (head.detail.SpanConfig && head.detail.SpanConfig.EtfKind) || '';
|
var kind = (head.detail.SpanConfig && head.detail.SpanConfig.EtfKind) || '';
|
||||||
var isTBond = ut === 16;
|
var isTBond = ut === 16;
|
||||||
var isTieredEtf = ut === FundTypeMask && TermTierEnabledEtfKinds.indexOf(kind) >= 0;
|
|
||||||
var isTiered = isTBond || isTieredEtf;
|
|
||||||
var sections = [];
|
var sections = [];
|
||||||
if (isTiered) {
|
if (isTBond) {
|
||||||
for (var t = 0; t < SpanBondTerms.length; t++) {
|
for (var t = 0; t < SpanBondTerms.length; t++) {
|
||||||
var found = null;
|
var found = null;
|
||||||
for (var j = head.index; j < head.index + head.rowspan; j++) {
|
for (var j = head.index; j < head.index + head.rowspan; j++) {
|
||||||
@@ -135,7 +129,7 @@ const vue = new Vue({
|
|||||||
} else {
|
} else {
|
||||||
sections.push({ key: 'single', termLabel: '', detail: head.detail });
|
sections.push({ key: 'single', termLabel: '', detail: head.detail });
|
||||||
}
|
}
|
||||||
blocks.push({ key: head.detail._bk || ('i' + head.index), no: blocks.length + 1, headIndex: head.index, ut: ut, etfKind: kind, isTBond: isTBond, isTieredEtf: isTieredEtf, isFundBlock: ut === FundTypeMask, sections: sections });
|
blocks.push({ key: head.detail._bk || ('i' + head.index), no: blocks.length + 1, headIndex: head.index, ut: ut, etfKind: kind, isTBond: isTBond, isFundBlock: ut === FundTypeMask, sections: sections });
|
||||||
}
|
}
|
||||||
return blocks;
|
return blocks;
|
||||||
}
|
}
|
||||||
@@ -432,64 +426,35 @@ const vue = new Vue({
|
|||||||
d.SpanConfig.EtfKind = etfKind || null;
|
d.SpanConfig.EtfKind = etfKind || null;
|
||||||
return d;
|
return d;
|
||||||
},
|
},
|
||||||
//ETF 子类选择器变更(仅纯基金区块渲染):选可转债/科创债 ETF → 区块展开固定4档(缺档补行、异常档行删除);
|
//ETF 子类选择器变更(仅纯基金区块渲染):子类仅用于行区分(取数侧子类行优先),
|
||||||
//选其他子类/不区分 → 收敛为单行(BondTerm 置空,多余档位行删除,首行承载 EtfKind)
|
//ETF 无期限概念不分档——任何子类切换后区块始终收敛为单行(BondTerm 置空,多余档位行删除,首行承载 EtfKind;
|
||||||
|
//存量 4 档子类数据在这里被收敛时仅保留首行录入内容)
|
||||||
onEtfKindChange(blk) {
|
onEtfKindChange(blk) {
|
||||||
var head = blk.sections[0].detail;
|
var head = blk.sections[0].detail;
|
||||||
var kind = (head.SpanConfig && head.SpanConfig.EtfKind) || '';
|
var kind = (head.SpanConfig && head.SpanConfig.EtfKind) || '';
|
||||||
var tiered = TermTierEnabledEtfKinds.indexOf(kind) >= 0;
|
|
||||||
var details = this.marginTemplate.Details;
|
var details = this.marginTemplate.Details;
|
||||||
var bk = head._bk;
|
var bk = head._bk;
|
||||||
var rows = details.filter(function (d) { return d._bk === bk; });
|
var rows = details.filter(function (d) { return d._bk === bk; });
|
||||||
if (tiered) {
|
rows.forEach(function (r) {
|
||||||
var byTerm = {};
|
if (r !== head) {
|
||||||
rows.forEach(function (r) {
|
|
||||||
var bt = (r.SpanConfig && r.SpanConfig.BondTerm) || '';
|
|
||||||
if (byTerm[bt] === undefined) byTerm[bt] = r;
|
|
||||||
});
|
|
||||||
var that = this;
|
|
||||||
var merged = [];
|
|
||||||
//首行未被4个合法档位命中时(单段行 BondTerm 为空)复用为首个档位行,保留已录入内容;
|
|
||||||
//否则首行会以"EtfKind 已选、BondTerm 为空"的残留行留在明细里,保存时被服务端"分期限档类型必须配置期限档"拦截
|
|
||||||
var headMatched = SpanBondTerms.some(function (t) { return byTerm[t[0]] === head; });
|
|
||||||
SpanBondTerms.forEach(function (t, ti) {
|
|
||||||
var r = byTerm[t[0]] || (ti === 0 && !headMatched ? head : null);
|
|
||||||
if (!r) r = that.newSpanDetail(FundTypeMask, t[0], kind);
|
|
||||||
r.UnderlyingType = FundTypeMask;
|
|
||||||
r.SpanConfig.EtfKind = kind;
|
|
||||||
r.SpanConfig.BondTerm = t[0];
|
|
||||||
Vue.set(r, '_bk', bk);
|
|
||||||
merged.push(r);
|
|
||||||
var idx = details.indexOf(r);
|
var idx = details.indexOf(r);
|
||||||
if (idx >= 0 && r !== head) details.splice(idx, 1);
|
if (idx >= 0) details.splice(idx, 1);
|
||||||
});
|
}
|
||||||
//异常档/重复行全部移除后按档序回插到区块首行位置
|
});
|
||||||
var headIdx = details.indexOf(head);
|
head.UnderlyingType = FundTypeMask;
|
||||||
if (headIdx < 0) headIdx = details.length;
|
head.SpanConfig.BondTerm = '';
|
||||||
details.splice.apply(details, [headIdx + 1, 0].concat(merged.filter(function (r) { return r !== head; })));
|
head.SpanConfig.EtfKind = kind || null;
|
||||||
} else {
|
|
||||||
rows.forEach(function (r) {
|
|
||||||
if (r !== head) {
|
|
||||||
var idx = details.indexOf(r);
|
|
||||||
if (idx >= 0) details.splice(idx, 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
head.UnderlyingType = FundTypeMask;
|
|
||||||
head.SpanConfig.BondTerm = '';
|
|
||||||
head.SpanConfig.EtfKind = kind || null;
|
|
||||||
}
|
|
||||||
this.refreshChosen();
|
this.refreshChosen();
|
||||||
},
|
},
|
||||||
//分档行判定与分档键:纯利率债 → 'tbond';基金 + 分档 ETF 子类 → 'etf:子类'(同一子类的连续行归一个区块)
|
//分档行判定与分档键:纯利率债 → 'tbond'(连续行归一个区块按固定4档补齐);ETF 子类不分档,基金行一律独立成块
|
||||||
spanTierKey(d) {
|
spanTierKey(d) {
|
||||||
var ut = d.UnderlyingType || 0;
|
var ut = d.UnderlyingType || 0;
|
||||||
var kind = (d.SpanConfig && d.SpanConfig.EtfKind) || '';
|
|
||||||
if (ut === TermTierEnabledUnderlyingMask) return 'tbond';
|
if (ut === TermTierEnabledUnderlyingMask) return 'tbond';
|
||||||
if (ut === FundTypeMask && TermTierEnabledEtfKinds.indexOf(kind) >= 0) return 'etf:' + kind;
|
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
//存量回显重建资产类型区块(分配区块键 _bk):连续的纯利率债行、基金+分档ETF子类行各自归为区块并按固定4档补齐(缺档补空行);
|
//存量回显重建资产类型区块(分配区块键 _bk):连续的纯利率债行归为区块并按固定4档补齐(缺档补空行);
|
||||||
//同档重复/异常档的分档行、非分档行(含基金+不分档子类、基金通配行)均各自独立成块展示,不丢数据
|
//同档重复/异常档的分档行、其余全部行(含基金+子类行、基金通配行)均各自独立成块展示,不丢数据——
|
||||||
|
//存量 ETF 子类 4 档行会以多个单行区块出现,保存时由服务端"ETF 子类不分期限档"校验拦截提示清理
|
||||||
rebuildSpanBlocks(details) {
|
rebuildSpanBlocks(details) {
|
||||||
var termValues = SpanBondTerms.map(function (t) { return t[0]; });
|
var termValues = SpanBondTerms.map(function (t) { return t[0]; });
|
||||||
var result = [];
|
var result = [];
|
||||||
@@ -511,13 +476,10 @@ const vue = new Vue({
|
|||||||
if (termValues.indexOf(bt) >= 0 && !byTerm[bt]) byTerm[bt] = r; else anomalies.push(r);
|
if (termValues.indexOf(bt) >= 0 && !byTerm[bt]) byTerm[bt] = r; else anomalies.push(r);
|
||||||
});
|
});
|
||||||
var bk = 'bk_' + (++spanBlockSeq);
|
var bk = 'bk_' + (++spanBlockSeq);
|
||||||
var utv = tk === 'tbond' ? TermTierEnabledUnderlyingMask : FundTypeMask;
|
|
||||||
var kind = tk === 'tbond' ? '' : tk.substring(4);
|
|
||||||
termValues.forEach(function (t) {
|
termValues.forEach(function (t) {
|
||||||
var r = byTerm[t];
|
var r = byTerm[t];
|
||||||
if (!r) r = that.newSpanDetail(utv, t, kind);
|
if (!r) r = that.newSpanDetail(TermTierEnabledUnderlyingMask, t);
|
||||||
r.UnderlyingType = utv;
|
r.UnderlyingType = TermTierEnabledUnderlyingMask;
|
||||||
if (kind) r.SpanConfig.EtfKind = kind;
|
|
||||||
r.SpanConfig.BondTerm = t;
|
r.SpanConfig.BondTerm = t;
|
||||||
Vue.set(r, '_bk', bk);
|
Vue.set(r, '_bk', bk);
|
||||||
result.push(r);
|
result.push(r);
|
||||||
@@ -549,15 +511,19 @@ const vue = new Vue({
|
|||||||
return map[v] !== undefined ? map[v] : v;
|
return map[v] !== undefined ? map[v] : v;
|
||||||
},
|
},
|
||||||
//规则15录入区块文案:按 detail 资产类型切换计价口径。
|
//规则15录入区块文案:按 detail 资产类型切换计价口径。
|
||||||
//债券类(利率债16/信用债32/其它债券64)及其他类型(默认债券口径):期初净价/当前净价,金额=×期初全价×券面总额;
|
//比较价格口径与计算侧对齐(MarginCalculationBase.CalcSwapSpanMaintenanceMargin:IsBond→中债估值净价,其余→收盘价):
|
||||||
//基金及基金专户(32768)/债券指数(536870912):参考标的期初净价/参考标的当前收盘价(空头各层统一收盘价,BUG-11 修正),
|
//纯债券类(利率债16/信用债32/其它债券64,可组合):期初净价/当前净价,金额=×期初全价×券面总额;
|
||||||
|
//其余全部类型(基金/债券指数/股票/股指等):参考标的期初净价/参考标的当前收盘价(多空各层统一收盘价),
|
||||||
//金额=×参考标的期初价格×参考标的名义份额。
|
//金额=×参考标的期初价格×参考标的名义份额。
|
||||||
spanText(detail) {
|
spanText(detail) {
|
||||||
var ut = (detail && detail.UnderlyingType) || 0;
|
var ut = (detail && detail.UnderlyingType) || 0;
|
||||||
if ((ut & 32768) > 0 || (ut & 536870912) > 0) {
|
//非空且标志位全部落在债券三类内才按债券口径;混合行(债券|非债券)按收盘价口径显示,与取数侧标的实际类型判定方向一致
|
||||||
|
var bondMask = 16 | 32 | 64;
|
||||||
|
var isBond = ut !== 0 && (ut & ~bondMask) === 0;
|
||||||
|
if (!isBond) {
|
||||||
return {
|
return {
|
||||||
priceInit: '参考标的期初净价',
|
priceInit: '参考标的期初净价',
|
||||||
priceCur: '参考标的当前净价',
|
priceCur: '参考标的当前收盘价',
|
||||||
priceCurShort1: '参考标的当前收盘价',
|
priceCurShort1: '参考标的当前收盘价',
|
||||||
priceCurShort: '参考标的当前收盘价',
|
priceCurShort: '参考标的当前收盘价',
|
||||||
amountBase: '参考标的期初价格 × 参考标的名义份额'
|
amountBase: '参考标的期初价格 × 参考标的名义份额'
|
||||||
@@ -633,5 +599,23 @@ $(function () {
|
|||||||
if (!isNaN(idx)) vue.onUnderlyingTypeChange(idx);
|
if (!isNaN(idx)) vue.onUnderlyingTypeChange(idx);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//多选 chosen:已有选中项后隐藏搜索框——空框没有输入内容却占一行,放不下时还会换行留白
|
||||||
|
//(本页多选均为点选场景,无需键盘过滤);全部取消后恢复,显示"请选择…"占位。
|
||||||
|
//勾选变化会触发原 select 的 jQuery change(trigger_form_field_change),
|
||||||
|
//加载重建/增删区块后的 refreshChosen 会触发 chosen:updated,两处都走这里的委托统一刷新
|
||||||
|
function refreshChosenSearchField(select) {
|
||||||
|
var $sel = $(select);
|
||||||
|
var $container = $sel.next('.chosen-container-multi');
|
||||||
|
if ($container.length === 0) return;
|
||||||
|
var noneSelected = $sel.find('option:selected').length === 0;
|
||||||
|
$container.find('li.search-field').toggle(noneSelected);
|
||||||
|
}
|
||||||
|
$(document).on('change chosen:updated', 'select.chosen-select[multiple]', function () {
|
||||||
|
refreshChosenSearchField(this);
|
||||||
|
});
|
||||||
|
|
||||||
SetAceDropDown();
|
SetAceDropDown();
|
||||||
|
$('select.chosen-select[multiple]').each(function () {
|
||||||
|
refreshChosenSearchField(this);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,585 +0,0 @@
|
|||||||
const consVarieties = ylotc.varieties;
|
|
||||||
const pricingFormat = otcformat.trading;
|
|
||||||
const consUnderlyingFlag = (function () {
|
|
||||||
let unSelFlag = tradeHelper.UnderlyingSelectFlag;
|
|
||||||
return unSelFlag.UseForTrading | unSelFlag.IncludeMatured | unSelFlag.UsePinYinFilter;
|
|
||||||
}());
|
|
||||||
|
|
||||||
var autoVariety, autoUnderlying;
|
|
||||||
|
|
||||||
function __init(vue) {
|
|
||||||
|
|
||||||
//标的品种
|
|
||||||
autoVariety = FastVue.autocomplete(document.getElementById('VarietyId'), {
|
|
||||||
lookup: consVarieties, nameField: 'Name', valueField: 'id', searchField: ['Name', 'Code', 'PinYin'],
|
|
||||||
onSelect: function (data) { vue.changeVariety(data, 'select'); }
|
|
||||||
});
|
|
||||||
|
|
||||||
//标的资产
|
|
||||||
autoUnderlying = tradeHelper.UnderlyingAutoComplete('UnderlyingCode').setFlag(consUnderlyingFlag);
|
|
||||||
autoUnderlying.onSelect(vue.changeunderlying);
|
|
||||||
|
|
||||||
//组合标的控件
|
|
||||||
synthenticPriceCtrl.init({
|
|
||||||
getSynthetic(input) {
|
|
||||||
return vue.viewState.synthetic;
|
|
||||||
},
|
|
||||||
setSynthetic(input, synthetic) {
|
|
||||||
vue.viewState.synthetic = synthetic;
|
|
||||||
vue.Model.SpotPrice = synthetic.Price;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
//标的控件初始化
|
|
||||||
if (vue.Model.UnderlyingCode) {
|
|
||||||
autoUnderlying.selectByCode(vue.Model.UnderlyingCode);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
autoUnderlying.selectFirst();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
var vue = new Vue({
|
|
||||||
el: "#listdiv",
|
|
||||||
data: {
|
|
||||||
Model: Model,
|
|
||||||
IsMoneynessOption: false
|
|
||||||
},
|
|
||||||
mounted: function () {
|
|
||||||
var thisObj = this;
|
|
||||||
//设置默认值补丁
|
|
||||||
thisObj.Model.ExerciseMode = "European";
|
|
||||||
thisObj.Model.TradeDate = moment(thisObj.Model.TradeDate).format("YYYY-MM-DD");
|
|
||||||
thisObj.Model.UnderlyingInstrumentType = "CommodityFutures";
|
|
||||||
$("#selUnderlyingInstrumentType").val("CommodityFutures");
|
|
||||||
__init(thisObj)
|
|
||||||
thisObj.setUnderlyingInstrumentType();
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
inputFormatStrike: function () {
|
|
||||||
let fmt = {};
|
|
||||||
if (this.Model.UnderlyingInstrumentType === 'Stock') {
|
|
||||||
fmt.append = '%';
|
|
||||||
fmt.negative = false;
|
|
||||||
fmt.precision = pricingFormat.premiumRateP.precision;
|
|
||||||
} else {
|
|
||||||
fmt.append = '';
|
|
||||||
fmt.negative = true;
|
|
||||||
fmt.precision = pricingFormat.umprice.precision;
|
|
||||||
}
|
|
||||||
return fmt;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
filters: {
|
|
||||||
ShowUnit: function (m) {
|
|
||||||
return m && m.Variety ? m.Variety.QuoteUnitSingle : "";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
ExerciseDateChange: function (data) {
|
|
||||||
var thisObj = this;
|
|
||||||
thisObj.Model.ExerciseDate = data;
|
|
||||||
},
|
|
||||||
ExerciseDateChange2: function (data) {
|
|
||||||
var thisObj = this;
|
|
||||||
thisObj.Model.ExerciseDate2 = data;
|
|
||||||
},
|
|
||||||
TradeDateChange: function (data) {
|
|
||||||
var thisObj = this;
|
|
||||||
thisObj.Model.TradeDate = data;
|
|
||||||
},
|
|
||||||
changeUnderlyingPrice: function () {
|
|
||||||
this.Model.UnderlyingPriceType = "User";
|
|
||||||
if (this.Model.UnderlyingInstrumentType !== "Stock") {
|
|
||||||
this.Model.StockEqvNotional = otcformat.trading.StockEqvNotional(this.Model.Notional * this.Model.Price);
|
|
||||||
this.Model.Price = otcformat.trading.umprice(this.Model.Price);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.Model.Notional = otcformat.trading.notional(this.Model.StockEqvNotional / this.Model.Price);
|
|
||||||
var CountRatio = this.Model.Variety.CountRatio || 1;
|
|
||||||
this.Model.TradeAmount = otcformat.trading.notional(this.Model.Notional / CountRatio);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
refreshUnderlyingPrice: function () {
|
|
||||||
var thisObj = this;
|
|
||||||
main.post("/underlying_manager/underlyingGetById", { id: thisObj.Model.UnderlyingId }).done(function (res) {
|
|
||||||
thisObj.Model.Price = otcformat.trading.umprice(res.underlying_manager.Price);
|
|
||||||
if (thisObj.Model.UnderlyingInstrumentType !== "Stock") {
|
|
||||||
thisObj.Model.StockEqvNotional = otcformat.trading.StockEqvNotional(thisObj.Model.Notional * thisObj.Model.Price);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
thisObj.Model.Notional = otcformat.trading.notional(thisObj.Model.StockEqvNotional / thisObj.Model.Price);
|
|
||||||
var CountRatio = thisObj.Model.Variety.CountRatio || 1;
|
|
||||||
thisObj.Model.TradeAmount = otcformat.trading.notional(thisObj.Model.Notional / CountRatio);
|
|
||||||
}
|
|
||||||
thisObj.$forceUpdate();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
setUnderlyingInstrumentType: function () {
|
|
||||||
var Underlying = $("#selUnderlyingInstrumentType").val();
|
|
||||||
autoUnderlying.selectFirst({ InstrumentTypes: Underlying });
|
|
||||||
},
|
|
||||||
changeunderlying: function (data) {
|
|
||||||
var thisObj = this;
|
|
||||||
thisObj.Model.VarietyId = data.VarietyId;
|
|
||||||
thisObj.Model.UnderlyingId = data.id;
|
|
||||||
thisObj.Model.UnderlyingCode = data.Code;
|
|
||||||
thisObj.Model.Variety = data;
|
|
||||||
thisObj.Model.Price = data.Price;
|
|
||||||
if (!data.Code) return;
|
|
||||||
thisObj.Model.UnderlyingInstrumentType = data.InstrumentType;
|
|
||||||
main.post("/Pricing/AjaxGetExerciseDate", { underlyingMaturityDate: data.MaturityDate, tradeDate: thisObj.Model.TradeDate }).done(function (res) {
|
|
||||||
thisObj.Model.ExerciseDate = new moment(res.obj.ExerciseDate).format("YYYY-MM-DD");
|
|
||||||
});
|
|
||||||
$.each(thisObj.Model.trades, function (i, d) {
|
|
||||||
d.MaturityDate = data.MaturityDate;
|
|
||||||
d.UnderlyingPrice = data.Price;
|
|
||||||
});
|
|
||||||
autoUnderlying.setVarietyId(data.VarietyId);
|
|
||||||
thisObj.changeVariety(data.VarietyId ? ylotc.varieties.find(x => x.id === data.VarietyId) : null);
|
|
||||||
thisObj.Model.Price = otcformat.trading.umprice(data.Price);
|
|
||||||
main.setTradeDatePicker("", "#ModelTradeDate", thisObj.Model.TradeDate, thisObj.TradeDateChange);
|
|
||||||
main.setTradeDatePicker("", "#ModelExerciseDate", thisObj.Model.ExerciseDate, thisObj.ExerciseDateChange);
|
|
||||||
main.setTradeDatePicker("", "#ModelExerciseDate2", thisObj.Model.ExerciseDate, thisObj.ExerciseDateChange2);
|
|
||||||
thisObj.IsMoneynessOption = thisObj.Model.UnderlyingInstrumentType === "Stock";
|
|
||||||
if (thisObj.IsMoneynessOption) {
|
|
||||||
thisObj.Model.StockEqvNotional = 1e6;
|
|
||||||
thisObj.changeStockEqvNotional();
|
|
||||||
} else {
|
|
||||||
thisObj.changeAmount();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setStrike: function (strikeType) {
|
|
||||||
if (this.Model.Name === "Condor") {
|
|
||||||
if (this.Model.Strike2 && this.Model.Strike3) {
|
|
||||||
if (this.Model.Strike2 >= this.Model.Strike3) {
|
|
||||||
if (strikeType === "Strike2") {
|
|
||||||
main.message("执行价格2需要小于执行价格3");
|
|
||||||
this.Model.Strike2 = "";
|
|
||||||
} else if (strikeType === "Strike3") {
|
|
||||||
main.message("执行价格3需要大于执行价格2");
|
|
||||||
this.Model.Strike3 = "";
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var diff = this.Model.Strike3 - this.Model.Strike2;
|
|
||||||
this.Model.Strike = this.Model.Strike2 - diff;
|
|
||||||
this.Model.Strike4 = parseFloat(this.Model.Strike3) + diff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.setStrike1();
|
|
||||||
},
|
|
||||||
setStrike1: function () {
|
|
||||||
this.Model.Strike = otcformat.trading.umprice(this.Model.Strike);
|
|
||||||
this.Model.Strike2 = otcformat.trading.umprice(this.Model.Strike2);
|
|
||||||
this.Model.Strike3 = otcformat.trading.umprice(this.Model.Strike3);
|
|
||||||
this.Model.Strike4 = otcformat.trading.umprice(this.Model.Strike4);
|
|
||||||
},
|
|
||||||
submitstructure: function () {
|
|
||||||
var thisObj = this;
|
|
||||||
if (thisObj.checkTrades()) {
|
|
||||||
thisObj.setModelTrades();
|
|
||||||
window.parent.vue.setOption(thisObj.Model.trades);
|
|
||||||
window.parent.layer.closeAll();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
close: function () {
|
|
||||||
window.parent.layer.closeAll();
|
|
||||||
},
|
|
||||||
checkTrades: function () {
|
|
||||||
var thisObj = this;
|
|
||||||
var pass = true;
|
|
||||||
var checkModel = { Strike12: true, Strike12Empty: true, CheckExerciseDate: true };
|
|
||||||
|
|
||||||
switch (thisObj.Model.Name) {
|
|
||||||
case "Butterfly":
|
|
||||||
checkModel.Strike12 = false;
|
|
||||||
checkModel.Strike12Empty = false;
|
|
||||||
thisObj.Model.MidStrike = thisObj.Model.Price;
|
|
||||||
if (!thisObj.Model.StrikeGap || !thisObj.Model.MidStrike) {
|
|
||||||
main.message("执行价格间距必填!"); pass = false;
|
|
||||||
}
|
|
||||||
if (parseFloat(thisObj.Model.MidStrike) <= parseFloat(thisObj.Model.StrikeGap)) {
|
|
||||||
main.message("标的价格必须大于行权价间隔!"); pass = false; //中间行权价 即 标的价格
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "Condor":
|
|
||||||
checkModel.Strike12 = false;
|
|
||||||
checkModel.Strike12Empty = false;
|
|
||||||
//验证行权价是否相同,从小到大排序,中间两个行权价允许相同,其他行权价不能相同
|
|
||||||
if (!thisObj.Model.Strike3 || !thisObj.Model.Strike4) {
|
|
||||||
main.message("行权价3,4必需输入!"); pass = false;
|
|
||||||
}
|
|
||||||
var strikes = [thisObj.Model.Strike, thisObj.Model.Strike2, thisObj.Model.Strike3, thisObj.Model.Strike4];
|
|
||||||
strikes.sort();
|
|
||||||
if (strikes[0] == strikes[1] || strikes[3] == strikes[2]) {
|
|
||||||
main.message("中间两个行权价允许相同,其他行权价不能相同!"); pass = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
//case "Preplicating Underlying":
|
|
||||||
case "Straddle":
|
|
||||||
//跨式组合的 执行价格 永远和标的价格一致
|
|
||||||
if (thisObj.Model.UnderlyingInstrumentType === "Stock") {
|
|
||||||
thisObj.Model.Strike = 100;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
thisObj.Model.Strike = thisObj.Model.Price;
|
|
||||||
}
|
|
||||||
checkModel.Strike12 = false;
|
|
||||||
checkModel.Strike12Empty = false;
|
|
||||||
if (!thisObj.Model.Strike) {
|
|
||||||
main.message("行权价必需输入!"); pass = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "Ratio Spread":
|
|
||||||
|
|
||||||
break;
|
|
||||||
case "Calender Spread"://ExerciseDate2
|
|
||||||
checkModel.Strike12 = false;
|
|
||||||
checkModel.Strike12Empty = false;
|
|
||||||
if (!thisObj.Model.ExerciseDate || !thisObj.Model.ExerciseDate2) {
|
|
||||||
main.message("两个到期日必需输入!"); pass = false;
|
|
||||||
}
|
|
||||||
if ((new Date(thisObj.Model.ExerciseDate)).getTime() <= (new Date(thisObj.Model.ExerciseDate2)).getTime()) {
|
|
||||||
main.message("到期日期2须早于到期日期1!"); pass = false;
|
|
||||||
}
|
|
||||||
if (!thisObj.Model.Strike) { main.message("请输入行权价!"); pass = false; }
|
|
||||||
break;
|
|
||||||
case "Collar":
|
|
||||||
checkModel.Strike12 = false;
|
|
||||||
checkModel.Strike12Empty = false;
|
|
||||||
if (!thisObj.Model.Strike || !thisObj.Model.Strike2 || !thisObj.Model.Strike3) {
|
|
||||||
main.message("执行价格1,2,3必需输入!"); pass = false;
|
|
||||||
}
|
|
||||||
if ((thisObj.Model.Strike == thisObj.Model.Strike2) || thisObj.Model.Strike == thisObj.Model.Strike3 || thisObj.Model.Strike3 == thisObj.Model.Strike2) {
|
|
||||||
main.message("执行价格1,2,3两两不能相等!"); pass = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!thisObj.Model.TradeAmount) {
|
|
||||||
main.message("请输入交易数量!"); pass = false;
|
|
||||||
}
|
|
||||||
if (thisObj.Model.TradeAmount < 0) {
|
|
||||||
main.message("交易数量不能小于0!"); pass = false;
|
|
||||||
}
|
|
||||||
if (checkModel.CheckExerciseDate) {
|
|
||||||
if (!main.isDate(thisObj.Model.ExerciseDate)) {
|
|
||||||
main.message("请输入正确的到期日!"); pass = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (checkModel.Strike12Empty && (!thisObj.Model.Strike || !thisObj.Model.Strike2)) { // Butterfly Condor 不必
|
|
||||||
main.message("执行价格1,2必需输入!"); pass = false;
|
|
||||||
}
|
|
||||||
return pass;
|
|
||||||
},
|
|
||||||
setModelTrades: function () {
|
|
||||||
var thisObj = this;
|
|
||||||
$.each(thisObj.Model.trades, function (i, d) {
|
|
||||||
d.VarietyId = thisObj.Model.VarietyId;
|
|
||||||
d.UnderlyingId = thisObj.Model.UnderlyingId;
|
|
||||||
d.UnderlyingCode = thisObj.Model.UnderlyingCode;
|
|
||||||
d.UnderlyingInstrumentType = thisObj.Model.UnderlyingInstrumentType;
|
|
||||||
d.Notional = thisObj.Model.Notional;
|
|
||||||
d.TradeAmount = otcformat.trading.notional(thisObj.Model.TradeAmount);
|
|
||||||
d.StockEqvNotional = thisObj.Model.StockEqvNotional;
|
|
||||||
d.ExerciseMode = thisObj.Model.ExerciseMode;
|
|
||||||
d.SettlementType = thisObj.Model.SettlementType;
|
|
||||||
if (thisObj.Model.OptionType)
|
|
||||||
d.OptionType = thisObj.Model.OptionType;
|
|
||||||
d.ExerciseDate = thisObj.Model.ExerciseDate;
|
|
||||||
d.TradeDate = thisObj.Model.TradeDate;
|
|
||||||
d.UnderlyingPrice = d.SpotPrice = thisObj.Model.Price;
|
|
||||||
d.NoRiskRateType = "System";
|
|
||||||
});
|
|
||||||
|
|
||||||
switch (thisObj.Model.Name) {
|
|
||||||
case "Bull Spread":
|
|
||||||
if (thisObj.Model.Strike < thisObj.Model.Strike2) {
|
|
||||||
thisObj.Model.trades[0].BuySell = "买入";
|
|
||||||
thisObj.Model.trades[1].BuySell = "卖出";
|
|
||||||
} else {
|
|
||||||
thisObj.Model.trades[0].BuySell = "卖出";
|
|
||||||
thisObj.Model.trades[1].BuySell = "买入";
|
|
||||||
}
|
|
||||||
thisObj.Model.trades[0].Strike = thisObj.Model.Strike;
|
|
||||||
thisObj.Model.trades[1].Strike = thisObj.Model.Strike2;
|
|
||||||
break;
|
|
||||||
case "Bear Spread":
|
|
||||||
if (thisObj.Model.Strike < thisObj.Model.Strike2) {
|
|
||||||
thisObj.Model.trades[0].BuySell = "卖出";
|
|
||||||
thisObj.Model.trades[1].BuySell = "买入";
|
|
||||||
} else {
|
|
||||||
thisObj.Model.trades[0].BuySell = "买入";
|
|
||||||
thisObj.Model.trades[1].BuySell = "卖出";
|
|
||||||
}
|
|
||||||
|
|
||||||
thisObj.Model.trades[0].Strike = thisObj.Model.Strike;
|
|
||||||
thisObj.Model.trades[1].Strike = thisObj.Model.Strike2;
|
|
||||||
thisObj.Model.Strike = thisObj.Model.Price;
|
|
||||||
break;
|
|
||||||
case "Straddle":
|
|
||||||
thisObj.Model.trades[0].BuySell = "买入";
|
|
||||||
thisObj.Model.trades[1].BuySell = "买入";
|
|
||||||
if (thisObj.Model.UnderlyingInstrumentType === "Stock") {
|
|
||||||
thisObj.Model.Strike = 100;
|
|
||||||
thisObj.Model.trades[0].Strike = 100;
|
|
||||||
thisObj.Model.trades[1].Strike = 100;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
thisObj.Model.Strike = thisObj.Model.Price;
|
|
||||||
thisObj.Model.trades[0].Strike = thisObj.Model.Strike;
|
|
||||||
thisObj.Model.trades[1].Strike = thisObj.Model.Strike;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case "Preplicating Underlying":
|
|
||||||
//交易方向“买入” 0看涨,1看跌
|
|
||||||
//两条leg 分别是: 买入执行价格高的看涨和卖出执行价格低看跌;
|
|
||||||
//交易方向为“卖出”:
|
|
||||||
//两条leg分别是:买入执行价格低的看跌和卖出执行价格高的看涨
|
|
||||||
//debugger;
|
|
||||||
thisObj.Model.trades[0].Strike = thisObj.Model.Strike;
|
|
||||||
thisObj.Model.trades[1].Strike = thisObj.Model.Strike2;
|
|
||||||
|
|
||||||
if (thisObj.Model.BuySell === "买入") {
|
|
||||||
if (thisObj.Model.trades[0].Strike > thisObj.Model.trades[1].Strike) {
|
|
||||||
thisObj.Model.trades[0].BuySell = "买入";
|
|
||||||
thisObj.Model.trades[0].OptionType = "看涨";
|
|
||||||
|
|
||||||
thisObj.Model.trades[1].BuySell = "卖出";
|
|
||||||
thisObj.Model.trades[1].OptionType = "看跌";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
thisObj.Model.trades[1].BuySell = "买入";//买入执行价格高的看涨
|
|
||||||
thisObj.Model.trades[1].OptionType = "看涨";
|
|
||||||
|
|
||||||
thisObj.Model.trades[0].BuySell = "卖出"; //看跌??
|
|
||||||
thisObj.Model.trades[0].OptionType = "看跌";
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (thisObj.Model.trades[0].Strike > thisObj.Model.trades[1].Strike) {
|
|
||||||
thisObj.Model.trades[0].BuySell = "买入"; //相对客户说??
|
|
||||||
thisObj.Model.trades[0].OptionType = "看涨";
|
|
||||||
|
|
||||||
thisObj.Model.trades[1].BuySell = "卖出";
|
|
||||||
thisObj.Model.trades[1].OptionType = "看跌";
|
|
||||||
} else {
|
|
||||||
thisObj.Model.trades[1].BuySell = "买入";
|
|
||||||
thisObj.Model.trades[1].OptionType = "看涨";
|
|
||||||
|
|
||||||
thisObj.Model.trades[0].BuySell = "卖出";
|
|
||||||
thisObj.Model.trades[0].OptionType = "看跌";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
thisObj.Model.Strike = thisObj.Model.Price;
|
|
||||||
break;
|
|
||||||
case "Strangle":
|
|
||||||
thisObj.Model.trades[0].BuySell = "买入";
|
|
||||||
thisObj.Model.trades[1].BuySell = "买入";
|
|
||||||
//thisObj.Model.Strike = thisObj.Model.Price;
|
|
||||||
thisObj.Model.trades[0].Strike = thisObj.Model.Strike;
|
|
||||||
thisObj.Model.trades[1].Strike = thisObj.Model.Strike2;
|
|
||||||
if (thisObj.Model.Strike >= thisObj.Model.Strike2) {
|
|
||||||
thisObj.Model.trades[0].OptionType = "看涨";
|
|
||||||
thisObj.Model.trades[1].OptionType = "看跌";
|
|
||||||
} else {
|
|
||||||
thisObj.Model.trades[0].OptionType = "看跌";
|
|
||||||
thisObj.Model.trades[1].OptionType = "看涨";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "Butterfly":
|
|
||||||
thisObj.Model.trades[0].BuySell = "买入";
|
|
||||||
thisObj.Model.trades[1].BuySell = "卖出";
|
|
||||||
thisObj.Model.trades[2].BuySell = "买入";
|
|
||||||
thisObj.Model.trades[0].Notional = thisObj.Model.Notional;
|
|
||||||
var CountRatio = thisObj.Model.Variety.CountRatio || 1;
|
|
||||||
thisObj.Model.trades[0].TradeAmount = otcformat.trading.notional(thisObj.Model.trades[0].Notional / CountRatio);
|
|
||||||
thisObj.Model.trades[1].Notional = thisObj.Model.Notional * 2;
|
|
||||||
thisObj.Model.trades[1].TradeAmount = otcformat.trading.notional(thisObj.Model.trades[1].Notional / CountRatio);
|
|
||||||
thisObj.Model.trades[2].Notional = thisObj.Model.Notional;
|
|
||||||
thisObj.Model.trades[2].TradeAmount = otcformat.trading.notional(thisObj.Model.trades[2].Notional / CountRatio);
|
|
||||||
//中间行权价-行权价间隔,中间行权价,中间行权价+行权价间隔
|
|
||||||
thisObj.Model.trades[0].Strike = thisObj.Model.MidStrike - thisObj.Model.StrikeGap;
|
|
||||||
thisObj.Model.trades[1].Strike = thisObj.Model.MidStrike;
|
|
||||||
thisObj.Model.trades[2].Strike = parseFloat(thisObj.Model.MidStrike) + parseFloat(thisObj.Model.StrikeGap);
|
|
||||||
break;
|
|
||||||
case "Condor":
|
|
||||||
thisObj.Model.trades[0].Strike = thisObj.Model.Strike;
|
|
||||||
thisObj.Model.trades[1].Strike = thisObj.Model.Strike2;
|
|
||||||
thisObj.Model.trades[2].Strike = thisObj.Model.Strike3;
|
|
||||||
thisObj.Model.trades[3].Strike = thisObj.Model.Strike4;
|
|
||||||
|
|
||||||
thisObj.Model.trades[0].OptionType = thisObj.Model.OptionType;
|
|
||||||
thisObj.Model.trades[1].OptionType = thisObj.Model.OptionType;
|
|
||||||
thisObj.Model.trades[2].OptionType = thisObj.Model.OptionType;
|
|
||||||
thisObj.Model.trades[3].OptionType = thisObj.Model.OptionType;
|
|
||||||
|
|
||||||
|
|
||||||
thisObj.Model.trades.sort(thisObj.strikeSort);
|
|
||||||
thisObj.Model.trades[0].BuySell = "买入";
|
|
||||||
thisObj.Model.trades[1].BuySell = "卖出";
|
|
||||||
thisObj.Model.trades[2].BuySell = "卖出";
|
|
||||||
thisObj.Model.trades[3].BuySell = "买入";
|
|
||||||
break;
|
|
||||||
case "Ratio Spread":
|
|
||||||
if (thisObj.Model.OptionType === "看涨") {
|
|
||||||
if (thisObj.Model.Strike < thisObj.Model.Strike2) {
|
|
||||||
thisObj.Model.trades[0].BuySell = "买入";
|
|
||||||
thisObj.Model.trades[1].BuySell = "卖出";
|
|
||||||
} else {
|
|
||||||
thisObj.Model.trades[0].BuySell = "卖出";
|
|
||||||
thisObj.Model.trades[1].BuySell = "买入";
|
|
||||||
}
|
|
||||||
} else if (thisObj.Model.OptionType === "看跌") {
|
|
||||||
if (thisObj.Model.Strike < thisObj.Model.Strike2) {
|
|
||||||
thisObj.Model.trades[0].BuySell = "卖出";
|
|
||||||
thisObj.Model.trades[1].BuySell = "买入";
|
|
||||||
} else {
|
|
||||||
thisObj.Model.trades[0].BuySell = "买入";
|
|
||||||
thisObj.Model.trades[1].BuySell = "卖出";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
thisObj.Model.trades[0].Notional = thisObj.Model.Notional;
|
|
||||||
var CountRatio = thisObj.Model.Variety.CountRatio || 1;
|
|
||||||
thisObj.Model.trades[0].TradeAmount = otcformat.trading.notional(thisObj.Model.trades[0].Notional / CountRatio);
|
|
||||||
thisObj.Model.trades[1].Notional = thisObj.Model.Notional2;
|
|
||||||
thisObj.Model.trades[1].TradeAmount = otcformat.trading.notional(thisObj.Model.trades[1].Notional / CountRatio);
|
|
||||||
thisObj.Model.trades[0].Strike = thisObj.Model.Strike;
|
|
||||||
thisObj.Model.trades[1].Strike = thisObj.Model.Strike2;
|
|
||||||
break;
|
|
||||||
case "Calender Spread":
|
|
||||||
if (thisObj.Model.ExerciseDate < thisObj.Model.ExerciseDate2) {
|
|
||||||
thisObj.Model.trades[0].BuySell = "卖出";
|
|
||||||
thisObj.Model.trades[1].BuySell = "买入";
|
|
||||||
} else {
|
|
||||||
thisObj.Model.trades[0].BuySell = "买入";
|
|
||||||
thisObj.Model.trades[1].BuySell = "卖出";
|
|
||||||
}
|
|
||||||
thisObj.Model.trades[0].ExerciseDate = thisObj.Model.ExerciseDate;
|
|
||||||
thisObj.Model.trades[1].ExerciseDate = thisObj.Model.ExerciseDate2;
|
|
||||||
thisObj.Model.trades[0].Strike = thisObj.Model.Strike;
|
|
||||||
thisObj.Model.trades[1].Strike = thisObj.Model.Strike;
|
|
||||||
break;
|
|
||||||
case "Box Spread":
|
|
||||||
thisObj.Model.trades[0].BuySell = "买入";
|
|
||||||
thisObj.Model.trades[1].BuySell = "卖出";
|
|
||||||
thisObj.Model.trades[2].BuySell = "买入";
|
|
||||||
thisObj.Model.trades[3].BuySell = "卖出";
|
|
||||||
|
|
||||||
thisObj.Model.trades[0].OptionType = "看涨";
|
|
||||||
thisObj.Model.trades[1].OptionType = "看跌";
|
|
||||||
thisObj.Model.trades[2].OptionType = "看跌";
|
|
||||||
thisObj.Model.trades[3].OptionType = "看涨";
|
|
||||||
if (thisObj.Model.Strike < thisObj.Model.Strike2) {
|
|
||||||
thisObj.Model.trades[0].Strike = thisObj.Model.Strike;
|
|
||||||
thisObj.Model.trades[1].Strike = thisObj.Model.Strike;
|
|
||||||
thisObj.Model.trades[2].Strike = thisObj.Model.Strike2;
|
|
||||||
thisObj.Model.trades[3].Strike = thisObj.Model.Strike2;
|
|
||||||
} else {
|
|
||||||
thisObj.Model.trades[0].Strike = thisObj.Model.Strike2;
|
|
||||||
thisObj.Model.trades[1].Strike = thisObj.Model.Strike2;
|
|
||||||
thisObj.Model.trades[2].Strike = thisObj.Model.Strike;
|
|
||||||
thisObj.Model.trades[3].Strike = thisObj.Model.Strike;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "Risk Reversal":
|
|
||||||
thisObj.Model.trades[0].Strike = Math.max(thisObj.Model.Strike, thisObj.Model.Strike2);
|
|
||||||
thisObj.Model.trades[1].Strike = Math.min(thisObj.Model.Strike, thisObj.Model.Strike2);
|
|
||||||
break;
|
|
||||||
case "Collar":
|
|
||||||
thisObj.Model.trades[0].OptionType = "看跌";
|
|
||||||
thisObj.Model.trades[1].OptionType = "看跌";
|
|
||||||
thisObj.Model.trades[2].OptionType = "看涨";
|
|
||||||
if (thisObj.Model.SeagullType === "Bullish") {
|
|
||||||
thisObj.Model.trades[1].OptionType = "看涨";
|
|
||||||
}
|
|
||||||
|
|
||||||
var strikes = [parseFloat(thisObj.Model.Strike), parseFloat(thisObj.Model.Strike2), parseFloat(thisObj.Model.Strike3)];
|
|
||||||
strikes.sort((x1, x2) => x1 - x2)
|
|
||||||
thisObj.Model.trades[0].Strike = strikes[0];
|
|
||||||
thisObj.Model.trades[1].Strike = strikes[1];
|
|
||||||
thisObj.Model.trades[2].Strike = strikes[2];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//设置初始化信息
|
|
||||||
$.each(thisObj.Model.trades, function (i, d) {
|
|
||||||
if (d.UnderlyingInstrumentType === "Stock") {
|
|
||||||
d.IsMoneynessOption = "是";
|
|
||||||
d.TradeSinglePriceType = "%";
|
|
||||||
d.IsUsePremiumRate = true;
|
|
||||||
}
|
|
||||||
d.Strike = otcformat.trading.umprice(d.Strike);
|
|
||||||
});
|
|
||||||
thisObj.buySellCalc();
|
|
||||||
},
|
|
||||||
strikeSort: function (tr1, tr2) {
|
|
||||||
return tr1.Strike - tr2.Strike;
|
|
||||||
},
|
|
||||||
buySellCalc: function () {
|
|
||||||
var thisObj = this;
|
|
||||||
if (thisObj.Model.BuySell === "卖出") {
|
|
||||||
//相反
|
|
||||||
$.each(thisObj.Model.trades, function (i, d) {
|
|
||||||
d.BuySell = d.BuySell === "卖出" ? "买入" : "卖出";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
addStructureOption: function () {
|
|
||||||
//增加交易策略
|
|
||||||
var thisObj = this;
|
|
||||||
main.open("/trade/GetStructureOption", thisObj.Model.Option).done(function (res) { });
|
|
||||||
},
|
|
||||||
changeAmount: function () { //交易数量= 份额 / 比率
|
|
||||||
var thisObj = this;
|
|
||||||
thisObj.Model.TradeAmount = otcformat.trading.notional(thisObj.Model.TradeAmount);
|
|
||||||
thisObj.Model.Notional = thisObj.Model.TradeAmount * (thisObj.Model.Variety.CountRatio || 1);
|
|
||||||
thisObj.Model.StockEqvNotional = otcformat.trading.StockEqvNotional(thisObj.Model.Notional * thisObj.Model.Price);
|
|
||||||
},
|
|
||||||
changeVariety: function (variety, flag) {
|
|
||||||
if (flag === 'select') {
|
|
||||||
if (this.Model.VarietyId === variety.id) return;
|
|
||||||
autoUnderlying.setVarietyId(variety.id);
|
|
||||||
autoUnderlying.selectFirst(variety.id);
|
|
||||||
} else {
|
|
||||||
autoVariety.setData(variety);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
changeStockEqvNotional: function () {
|
|
||||||
var thisObj = this;
|
|
||||||
thisObj.Model.Notional = otcformat.trading.notional(thisObj.Model.StockEqvNotional / thisObj.Model.Price);
|
|
||||||
if (thisObj.Model.Notional) {
|
|
||||||
thisObj.Model.TradeAmount = otcformat.trading.notional(thisObj.Model.Notional / (thisObj.Model.Variety.CountRatio || 1));
|
|
||||||
} else {
|
|
||||||
thisObj.Model.TradeAmount = "";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
//绝对值执行价格
|
|
||||||
showAbsStrike() {
|
|
||||||
this.IsMoneynessOption = false;
|
|
||||||
this.moneynessSwitch(this.trade);
|
|
||||||
},
|
|
||||||
//百分比执行价格
|
|
||||||
showPercentStrike() {
|
|
||||||
this.IsMoneynessOption = true;
|
|
||||||
this.moneynessSwitch(this.trade);
|
|
||||||
},
|
|
||||||
moneynessSwitch(trade) {
|
|
||||||
let spotPrice = parseFloat(this.Model.Price) || 0;
|
|
||||||
let isSpotZero = Math.abs(spotPrice) < 1e-4;
|
|
||||||
let strikes = ["Strike", "Strike2", "Strike3", "Strike4"];
|
|
||||||
for (var key of strikes) {
|
|
||||||
if (this.IsMoneynessOption) {
|
|
||||||
this.Model[key] = pricingFormat.premiumRate(isSpotZero ? 1 : this.Model[key] / spotPrice);
|
|
||||||
} else {
|
|
||||||
this.Model[key] = pricingFormat.umprice(this.Model[key] * spotPrice);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
'vue-number-input': FastVue.vueNumberInput()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,24 +0,0 @@
|
|||||||
$(function () {
|
|
||||||
var table = $("#infoTable")[0];
|
|
||||||
pageObj.SacInfoList.forEach(Obj => {
|
|
||||||
formatHtml(Obj, table, 1);
|
|
||||||
})
|
|
||||||
})
|
|
||||||
function formatHtml(obj, table, rowIndex) {
|
|
||||||
if (obj.FieldName !== "Root" && obj.FieldName !== "Header" && obj.FieldName !== "Body") {
|
|
||||||
var html = '<td title="{0}">{1}</td><td>{2}</td><td>{3}</td>'.template(obj.FieldName, obj.FieldDescribe, obj.FieldValue, obj.ShowMessage);
|
|
||||||
rowIndex = addRow(table, rowIndex, html);
|
|
||||||
}
|
|
||||||
if (obj.SubInfos && obj.SubInfos.length > 0) {
|
|
||||||
obj.SubInfos.forEach(function (item) {
|
|
||||||
rowIndex = formatHtml(item, table, rowIndex);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return rowIndex;
|
|
||||||
}
|
|
||||||
function addRow(table, rowIndex, htmlStr) {
|
|
||||||
var row = table.insertRow(rowIndex);
|
|
||||||
row.innerHTML = htmlStr;
|
|
||||||
rowIndex += 1;
|
|
||||||
return rowIndex;
|
|
||||||
}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
//roleFunctionEdit.cshtml
|
|
||||||
|
|
||||||
function autocheck(a) {
|
|
||||||
$("input[id={0}]".template(a.id)).prop("checked", a.checked);
|
|
||||||
linkage(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
function linkage(a) {
|
|
||||||
var obj = $(a);
|
|
||||||
var parentName = obj.attr('data-parent');
|
|
||||||
var status = $(a).is(":checked");
|
|
||||||
var typeName = obj.attr('data-type');
|
|
||||||
var fname = obj.attr('lang');
|
|
||||||
if (parentName === "-") {
|
|
||||||
$(obj).next().css('display', 'none');
|
|
||||||
$('input[type="checkbox"][data-parent="{0}"][data-type="{1}"]'.template(fname, typeName)).prop("checked", status);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var arr = $("input[type='checkbox'][data-parent='{0}'][data-type='{1}']".template(parentName, typeName));
|
|
||||||
var parSelector = 'input[type="checkbox"][lang="{0}"][data-type="{1}"]'.template(parentName, typeName);
|
|
||||||
$(parSelector).next().css('display', 'none');
|
|
||||||
var continueState = false;
|
|
||||||
$(arr).each(function (i, obj) {
|
|
||||||
if ($(obj).is(":checked") != status) {
|
|
||||||
$(parSelector).prop("checked", true);
|
|
||||||
$(parSelector).next().css('display', 'inline-block');
|
|
||||||
continueState = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (!continueState) {
|
|
||||||
$(parSelector).prop("checked", status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function GoBack() {
|
|
||||||
if (document.all) { //ie
|
|
||||||
if (window.history.length > 0) {
|
|
||||||
window.history.back();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (window.history.length > 1) {
|
|
||||||
window.history.back();
|
|
||||||
} else {
|
|
||||||
window.opener = null;
|
|
||||||
window.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
window.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
function showOrHide(res) {
|
|
||||||
if ($(res).text() === "-") {
|
|
||||||
$(res).parent().next().next().hide();
|
|
||||||
$(res).html("+");
|
|
||||||
} else {
|
|
||||||
$(res).parent().next().next().show();
|
|
||||||
$(res).html("-");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function modulePermissions() {
|
|
||||||
$(".tab-1").parent().addClass("active");
|
|
||||||
$(".tab-link").parent().removeClass("active");
|
|
||||||
|
|
||||||
$(".tab-content").removeClass("tab-none");
|
|
||||||
$(".tab-content2").addClass("tab-none");
|
|
||||||
$(".tab-content2").removeClass("tab-block");
|
|
||||||
}
|
|
||||||
function operationPeemissions() {
|
|
||||||
$(".tab-link").parent().addClass("active");
|
|
||||||
$(".tab-1").parent().removeClass("active");
|
|
||||||
$(".tab-content").addClass("tab-none");
|
|
||||||
$(".tab-content2").addClass("tab-block");
|
|
||||||
|
|
||||||
}
|
|
||||||
$(".spanleft").parent().addClass("spanleft-w");
|
|
||||||
|
|
||||||
$(document).ready(function () {
|
|
||||||
var parentArr = $("input[type='checkbox'][data-parent='-']");
|
|
||||||
$(parentArr).each(function (i, obj) {
|
|
||||||
var dataType = $(obj).attr("data-type")
|
|
||||||
var allCount = $('input[type="checkbox"][data-parent="{0}"][data-type="{1}"]'.template(obj.lang, dataType)).length;
|
|
||||||
var selectCount = $('input[type="checkbox"][data-parent="{0}"][data-type="{1}"]:checked'.template(obj.lang, dataType)).length;
|
|
||||||
if (allCount != selectCount && selectCount > 0) {
|
|
||||||
$(obj).next().css('display', 'inline-block');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
modulePermissions();
|
|
||||||
main.form({
|
|
||||||
el: '#roleFunctionEditForm',
|
|
||||||
submit: {
|
|
||||||
url: '/system/roleFunctionEditFormJson',
|
|
||||||
after(res) {
|
|
||||||
window.location.href = "/system/RoleView?id=" + res.obj.Id;
|
|
||||||
try {
|
|
||||||
window.parent && window.parent.SearchClick();
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -17,6 +17,10 @@
|
|||||||
const consSelect = ['MarketCode', 'UnderlyingInstrumentType', 'UnderlyingState', 'UnderlyingStatus', 'UpDownLimitType', 'EtfSubType'];
|
const consSelect = ['MarketCode', 'UnderlyingInstrumentType', 'UnderlyingState', 'UnderlyingStatus', 'UpDownLimitType', 'EtfSubType'];
|
||||||
|
|
||||||
var autoUpDownLimit, autoVariety;
|
var autoUpDownLimit, autoVariety;
|
||||||
|
var fundManagerLookupSeq = 0;
|
||||||
|
var fundManagerLookupTimer = null;
|
||||||
|
var fundManagerLookupXhr = null;
|
||||||
|
var fundManagerManualEdit = false;
|
||||||
|
|
||||||
$(function () {
|
$(function () {
|
||||||
|
|
||||||
@@ -46,6 +50,12 @@ $(function () {
|
|||||||
lookup: ylotc.varieties
|
lookup: ylotc.varieties
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#InvestAdvisorName').on('input', function () {
|
||||||
|
fundManagerManualEdit = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#UnderlyingCode').on('input', refreshFundManagerLookup);
|
||||||
|
|
||||||
for (var i = 1; i <= 5; i++) {
|
for (var i = 1; i <= 5; i++) {
|
||||||
let datas = ylotc.underlyingBlocks.filter(x => x.Group === i);
|
let datas = ylotc.underlyingBlocks.filter(x => x.Group === i);
|
||||||
let autoBlock = FastVue.autocomplete(document.getElementById('inputBlock' + i), {
|
let autoBlock = FastVue.autocomplete(document.getElementById('inputBlock' + i), {
|
||||||
@@ -112,9 +122,57 @@ $(function () {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$('#editForm').removeClass("form-None form-Stock form-CommodityFutures form-CommoditySpot form-Bonds form-Fund").addClass("form-" + classType);
|
$('#editForm').removeClass("form-None form-Stock form-CommodityFutures form-CommoditySpot form-Bonds form-Fund").addClass("form-" + classType);
|
||||||
|
refreshFundManagerLookup();
|
||||||
}).trigger('change');
|
}).trigger('change');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function refreshFundManagerLookup() {
|
||||||
|
var requestSeq = ++fundManagerLookupSeq;
|
||||||
|
if (fundManagerLookupTimer) {
|
||||||
|
clearTimeout(fundManagerLookupTimer);
|
||||||
|
fundManagerLookupTimer = null;
|
||||||
|
}
|
||||||
|
if (fundManagerLookupXhr) {
|
||||||
|
fundManagerLookupXhr.abort();
|
||||||
|
fundManagerLookupXhr = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var codeInput = $('#UnderlyingCode');
|
||||||
|
var typeInput = $('#UnderlyingInstrumentType');
|
||||||
|
var managerInput = $('#InvestAdvisorName');
|
||||||
|
if (page.Model.id > 0 || !codeInput.length || !typeInput.length ||
|
||||||
|
typeInput.val() !== 'Fund' || !codeInput.val() || !managerInput.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var codeAtRequest = codeInput.val();
|
||||||
|
var managerAtRequest = managerInput.val() || '';
|
||||||
|
var manualAtRequest = fundManagerManualEdit;
|
||||||
|
fundManagerLookupTimer = setTimeout(function () {
|
||||||
|
fundManagerLookupTimer = null;
|
||||||
|
fundManagerLookupXhr = $.ajax({
|
||||||
|
url: '/underlying_manager/GetFundManager',
|
||||||
|
method: 'GET',
|
||||||
|
data: { code: codeAtRequest, instrumentType: 'Fund' }
|
||||||
|
}).done(function (resp) {
|
||||||
|
if (requestSeq !== fundManagerLookupSeq || page.Model.id > 0 ||
|
||||||
|
$('#UnderlyingCode').val() !== codeAtRequest ||
|
||||||
|
$('#UnderlyingInstrumentType').val() !== 'Fund' ||
|
||||||
|
manualAtRequest || fundManagerManualEdit) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = resp && resp.obj;
|
||||||
|
if (result && result.IsUnique && result.InvestAdvisorName) {
|
||||||
|
managerInput.val(result.InvestAdvisorName);
|
||||||
|
fundManagerManualEdit = false;
|
||||||
|
}
|
||||||
|
}).always(function () {
|
||||||
|
fundManagerLookupXhr = null;
|
||||||
|
});
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
|
||||||
function saveData() {
|
function saveData() {
|
||||||
|
|
||||||
var data = $('#editForm').serializeObject();
|
var data = $('#editForm').serializeObject();
|
||||||
|
|||||||
@@ -62,9 +62,9 @@
|
|||||||
padding: 5px;
|
padding: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chosen-container-multi .chosen-choices li.search-choice {
|
/*多选 chosen 的 search-choice 已去掉原固定 130px 宽(改由 chosen 默认自适应):
|
||||||
width: 130px;
|
固定宽会让短标签(买入/收益互换等)右侧大片留白,并把隐藏的搜索输入框挤到下一行、撑出一截空白高度。
|
||||||
}
|
下方 span:first-child 120px 是单选 chosen 选中项的旧规则,与多选无关*/
|
||||||
|
|
||||||
.form-layout .chosen-choices > li > span:first-child, .searchdiv .chosen-choices .search-choice > span:first-child {
|
.form-layout .chosen-choices > li > span:first-child, .searchdiv .chosen-choices .search-choice > span:first-child {
|
||||||
width: 120px;
|
width: 120px;
|
||||||
@@ -89,14 +89,83 @@ p {
|
|||||||
padding-bottom: unset;
|
padding-bottom: unset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*区间追保结构区块:单元格里多个数字输入与文字并列,全局 input[type=text] 152px 会把单元格内容挤成两行,调窄保证单行*/
|
/*区间追保结构区块:单元格里多个数字输入与文字并列,全局 input[type=text] 152px 会把单元格内容挤成两行;
|
||||||
|
64px 保证 100.00% 这类两位小数百分比完整显示且不换行*/
|
||||||
.spanBlk table input[type=text] {
|
.spanBlk table input[type=text] {
|
||||||
width: 50px;
|
width: 64px;
|
||||||
padding-left: 2px;
|
padding-left: 2px;
|
||||||
padding-right: 2px;
|
padding-right: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*同区块表格单元格边距:bootstrap .table 默认 0.75rem,压缩使表格更紧凑*/
|
/*同区块表格单元格边距:bootstrap .table 默认 0.75rem,压缩使表格更紧凑;垂直居中使公式文字与输入框对齐*/
|
||||||
.spanBlk table th, .spanBlk table td {
|
.spanBlk table th, .spanBlk table td {
|
||||||
padding: 2px 4px;
|
padding: 2px 4px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*左栏基础信息列(tpl-base 标记在三个编辑页共用的左侧 col 上):
|
||||||
|
控件统一 240px 宽、右缘对齐;多选 chosen 初始化取 select 宽度(SetAceDropDown),随之统一。
|
||||||
|
说明类 textarea 跟随列宽(减去 160px 标签 + 8px 间距 + 4px 余量)*/
|
||||||
|
.tpl-base {
|
||||||
|
/*左右两栏约 1:2:左栏基础信息收窄,右侧追保区间表格更宽。
|
||||||
|
不用 col-md-5/7:form-layout 自带 1rem 外边距,两栏 basis 相加已满 100% 会折行;
|
||||||
|
左栏定宽(不缩不放)+ 右栏 .col(flex:1) 吸收剩余宽度,无折行风险*/
|
||||||
|
flex: 0 0 34%;
|
||||||
|
max-width: 34%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tpl-base input.text-box,
|
||||||
|
.tpl-base select {
|
||||||
|
width: 240px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tpl-base textarea.text-box {
|
||||||
|
width: calc(100% - 172px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*只读说明(规则描述/分类说明):禁用输入框的灰底边框观感突兀,弱化为说明文字块;
|
||||||
|
保留滚动(规则描述较长),滚动条细化*/
|
||||||
|
.tpl-base textarea.text-box:disabled {
|
||||||
|
background: #f8f8f8;
|
||||||
|
border: none;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: #777;
|
||||||
|
resize: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tpl-base textarea.text-box:disabled::-webkit-scrollbar {
|
||||||
|
width: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*多选 chosen:有选中项后由页面 JS 隐藏搜索框(见 marginTemplateV2*Edit.js 的 refreshChosenSearchField),
|
||||||
|
空态时搜索框独占控件全宽,负责展示"请选择…"占位*/
|
||||||
|
|
||||||
|
/*期限档位表操作列:delBtn 的 20px 左边距在 fixed 布局的窄列里会把"- 删除区块"挤成竖排*/
|
||||||
|
.border.detail td .delBtn {
|
||||||
|
margin-left: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*区块标题(新模板信息/选择模板规则/参数组N):左色条 + 加粗,与表单正文分层*/
|
||||||
|
.border > p:first-child {
|
||||||
|
font-weight: bold;
|
||||||
|
border-left: 3px solid #e33333;
|
||||||
|
padding-left: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*参数组区块外边界加深:区块内表格线是浅灰,外框同步太浅导致分组不明显*/
|
||||||
|
.spanBlk.border {
|
||||||
|
border-color: #9e9e9e !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*期限档位区块表:固定布局让"标的资产类型"列吃剩余宽度,期限档位/操作按内容定宽,
|
||||||
|
避免两列均分 100% 时操作列被撑得过宽、与内容不成比例*/
|
||||||
|
.border.detail table {
|
||||||
|
table-layout: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*标的资产类型多选(期限档位表单元格内):chosen 初始化取原生 select 的固有宽度(约 150px),
|
||||||
|
窄容器放不下第二个已选标签,导致标签逐行竖排;单元格空间充足,容器撑满即可横向排列*/
|
||||||
|
.border.detail .chosen-container-multi {
|
||||||
|
width: 100% !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,125 @@
|
|||||||
|
# 旧保证金链路存亡分析与下线重构方案
|
||||||
|
|
||||||
|
- 日期:2026-08-28
|
||||||
|
- 分析基线:`glms/feature/1.4.2` @ `cd615a61`
|
||||||
|
- 背景:2026-08-26 `4adfbabe`(配套 `134e07c6`/`1969e292`)将互换预付金 EOD 计算收口为本端 .NET 引擎(`EodWorstClientPayableCalc` + `MarginTemplateV2RateHelper`,读 `margin_template_v2`),不再经 bond-oms Java 按旧 `marginrate` 数据算盯市。本文回答:**山证 v2.3.0 拷贝带过来的旧保证金相关代码(DMA 与否),在新引擎上线后还剩多少活口、如何分阶段下线。**
|
||||||
|
|
||||||
|
## 一、结论总览
|
||||||
|
|
||||||
|
| # | 链路 | 判定 | 一句话依据 |
|
||||||
|
|---|------|------|-----------|
|
||||||
|
| 1 | bond-oms HTTP 保证金接口(`/marginAlgorithm/realTimeMarginCalc` ← `CalcDMAMargin`) | **死,可删** | 全仓(含 YLWinSer/前端/配置)零调用方;`git log -S` 全历史自拷贝日起从未被调用 |
|
||||||
|
| 2 | `margin_template` V1 模板管理链 | **部分可删** | 计算链已全部 V2 化;但 5 个 Razor 页面的模板下拉仍喂 V1 表 |
|
||||||
|
| 3 | `client_marginrate` 旧预付金率链(MarginRateSwap) | **半死** | EOD 盯市消费方已随收口消失;剩 2 条活读链(流水导入落快照、录入页取率回显) |
|
||||||
|
| 4 | `MarginRate`(不带 Swap)+ 远期保证金链 | **远期结算确定死;其余需业务确认** | `EodForwardMarginSettlement` 2025-04-16 已从 EOD 调度摘除,零调用方 |
|
||||||
|
| 5 | DMA 分类(`Client.SwapTradeType`) | **活,但仅 2 处真实分支** | 其余全是透传展示与命名误导;`CalcDMAMargin` 死代码不影响判定 |
|
||||||
|
|
||||||
|
## 二、分链详解
|
||||||
|
|
||||||
|
### 2.1 bond-oms HTTP 保证金接口(死,可删)
|
||||||
|
|
||||||
|
接口本体在 bond-oms Java 服务(`BondOmsInterface.BaseUrl = trs_hub_api`),本仓是唯一已知调用方,而调用方本身是死的:
|
||||||
|
|
||||||
|
| 层 | 位置 | 状态 |
|
||||||
|
|---|---|---|
|
||||||
|
| 调用点 | `YLErpDAL/BLL/EodSettlement/RealtimePnlCalc.cs:722` `CalcDMAMargin()` | 全仓无任何调用方(全文件类型 grep) |
|
||||||
|
| 方法内 URL | `RealtimePnlCalc.cs:725` 硬编码 | 随方法一起死 |
|
||||||
|
| 配置键 | `YLWinSer/RealTimeCalcPositionService/appsettings.json:48` `CalculateDMAMarginUrl` | 无任何代码读取(URL 是硬编码的,配置键是摆设) |
|
||||||
|
| DTO | `YLErpDAL/Model/CalculateMarginRequest.cs` | 仅被 `CalcDMAMargin` 使用,可连带删 |
|
||||||
|
|
||||||
|
排除项:YLWinSer 常驻任务(ClientPosiTask/Worker/ClientNoDMABalanceTask)不调它;YLErpWeb 无 `marginAlgorithm` 路由/代理,前端(含 Vue3 仓)架构上不可达;无反射/字符串调度。
|
||||||
|
|
||||||
|
**历史证据**:`git log -S "CalcDMAMargin()" --all` 仅两条 —— `f9d8a256`(山证拷贝,方法进仓)与 `4adfbabe`(只加注释)。即该方法从进仓第一天起就从未被调用,山证原版的 DMA 任务未随拷贝进来(本仓只有 `ClientNoDMABalanceTask`)。
|
||||||
|
|
||||||
|
**注意**:`EodCheckMonitoredTrade.cs:186` 注释(4adfbabe 加)把 `CalcDMAMargin` 描述为"迁移方案阶段三待切项"——与事实不符(无流量可切),删码时必须同步修正,否则迁移计划继续被带偏。
|
||||||
|
|
||||||
|
Java 端点能否删需在 bond-oms 仓自查内部调度,本仓证据只能证明"本仓侧调用链已死"。
|
||||||
|
|
||||||
|
### 2.2 margin_template V1 模板链(部分可删)
|
||||||
|
|
||||||
|
**计算链已全部 V2 化,无 V1 回退**:
|
||||||
|
- 核心预付金:`MarginCalculationBase.cs:392,420` → `MarginTemplateV2RateHelper`(纯 V2 三级解析)
|
||||||
|
- 追保/span:`SwapAdditionalMarginService.cs:115`、`SwapSpanBalanceQueryService.cs:91` 均走 V2 helper
|
||||||
|
- 交易保存:`SwapTradeService.cs:162-209` 只查 `margin_template_v2` 并写 `trade_margin_template`(存 V2 id);`TradeSaveService.cs:654-697`、`TradeQueryService.cs:324`、`SwapMarginTemplateConfigService.cs:17` 同
|
||||||
|
- V1 管理页入口已死:`Menus.txt` 仅剩指向 V2;`margin_templateController.cs:9` 引用的 FunctionRight 权限已不存在
|
||||||
|
|
||||||
|
**V1 表仅剩 2 类活读点**:
|
||||||
|
1. `tradeController.cs:8861/8873`(`GetMarginTemplates`/`GetMarginTemplateItems`,直接 `db.margin_template.ToList()`),被 5 个在用页面 Razor 服务端调用做模板名下拉:
|
||||||
|
`Views/SwapTrade2/TradeEdit.cshtml:17,33`、`Views/SwapTrade/tradeEdit.cshtml:15-16`、`Views/trade/TradeEditV2.cshtml:20-21`(远期编辑)、`Views/Pricing/Structure_DZ.cshtml:22-23`、`Views/Pricing/structure.cshtml`
|
||||||
|
2. `ForwardTradeImportService.cs:318-352,872` 远期导入消费 V1 比率(远期业务本身存亡见 2.4)
|
||||||
|
|
||||||
|
**不可删(易误伤)**:`client_margin_template` 已 V2 化,是 V2 引擎第二级数据源(`MarginTemplateV2RateHelper.cs:256,341`、`ClientBalanceUtility.cs:631`);`margin_template_detail`、`trade_margin_template` 是 V2 的表,与 V1 同名前缀但归属 V2。
|
||||||
|
|
||||||
|
### 2.3 client_marginrate 旧预付金率链(半死)
|
||||||
|
|
||||||
|
无独立 margin_rate_swap 表,整条链落在 `client_marginrate` 表(`Framework/YLErp.Core/DBModels/client_marginrate.cs:8`)。
|
||||||
|
|
||||||
|
- **写入/维护链**:菜单入口已于 `ab907122`(2026-08-12,EQD-6947)注释下线(Menus.txt:81-82"由预付金模板V2替代");`MarginRateSwapController` 的 CRUD/导入 action 仍可直接 URL 访问,FunctionRight 权限残留。
|
||||||
|
- **活读链(仅剩 2 条)**:
|
||||||
|
1. 流水导入:`SwapTradeFlowImportService.cs:351-354` 按 客户+品种+日期 取 `client_marginrate` → `:374` `InitialMargin = marginRate * StockEqvNotional` → `:393` 落 `trade_swap.GetMarginRate` 快照(TradeSwapService 8 处调用)
|
||||||
|
2. 录入取率回显:`SwapTradeController.cs:1152` `GetInitMarginRate` → `swapTradeEdit.js`(互换录入页实时回显)
|
||||||
|
- **死读点**:`RealTimeClientBanlanceService.cs:1469` 加载后从未使用;`ClientBalanceUtility.cs:1517`、`ConfirmationGenerateContext.cs:1913`、`ITradeDocGeneratorContext.cs:443` 全仓零调用;`SwapTradeValidator` 只看 `trade_swap.GetMarginRate` 快照,`:24` 的调用已注释。
|
||||||
|
- **与新引擎零交叉**:已逐一确认 `EodWorstClientPayableCalc`、`MarginTemplateV2RateHelper`、`RealtimePnlCalc`、`SwapSpanBalanceCalc`、`SwapAdditionalMarginService` 均不读 `client_marginrate`;无 SQL/Dapper/存储过程读点;YLWinSer 无相关任务。
|
||||||
|
|
||||||
|
### 2.4 MarginRate(不带 Swap)+ 远期链
|
||||||
|
|
||||||
|
- **`EodForwardMarginSettlement` 确定死**:`8e61f23e`(2025-04-16)已将其从 EOD 调度摘除,现全仓零调用方;`eod_forward_margin` 表唯一写入点随之失活,读方(`EodPositionSettleService.cs:870,967`、`RealtimePnlCalc.cs:1009`、`TradeForwardUnwindService.cs:96`)全部空转。`SettlementConfig.CalcForwradMargin` 零消费。
|
||||||
|
- **Forward 模块整体**:拷贝后零提交改动;录入页/导入/11 个 Views/API 均在,菜单在 DB `sys_menu`(仓内无法证明挂没挂);`tradeController.cs:6295` 仅渤海/广发商贸分支才查远期。**需业务确认**(菜单是否还挂、trade 表有无远期存量)。
|
||||||
|
- **`MarginRate` CRUD/导入**:UI 自闭环;表读方仅 `SwapTradeFlowImportService.cs:337`(且被 `PS.Config.Company==中金` 门控,本部署非中金)与 `VarietyDalService.cs:426`(防删校验);`GetMarginRate`(`MarginRateService.cs:210`)零调用。
|
||||||
|
- **`MarginParamProvider` 不可删**:`MarginCalcHelper.cs:30`(活引擎 `RunMarginCalculation` 内)与 `TradeDelaySettlementService.cs:72,163` 在用其涨跌幅/波动率;其预付金率读法(`:149-160`)才是死的。
|
||||||
|
|
||||||
|
### 2.5 DMA 概念:字段活,概念基本只剩命名
|
||||||
|
|
||||||
|
字段 = `Client.SwapTradeType`(`Client.cs:1149`,1=DMA/MDA,0=非DMA)。**真实分支仅 2 处**:
|
||||||
|
1. `QuotaMonitorService.cs:5591` `CheckFund`:`SwapTradeType==0` 非 DMA 不做资金校验直接过(经 `RunQuotaTrial` ← `tradeController.cs:8502` 限额试算,活)
|
||||||
|
2. `YLErpWeb/App/KafkaTask/ClientBalanceTask.cs:62`:DMA 客户 `lastBalanceDate=valuedate`(起算日改为当日),活
|
||||||
|
|
||||||
|
其余全部是透传/展示/命名:`ClientSettleBalance.ClientTypeStr`、`ClientBalanceUtility`、`RealTimeClientBanlanceService`、监控/报表 js、客户编辑下拉等;`SwapFlowCombookingHub.cs:79` "DMA合成持仓" 只是 region 名(DMA 过滤已注释,与 DMA 无关,Hub 本身有前端连接方,活);`ClientNoDMABalanceTask` 的 "NoDMA" 纯任务名,`GetBalances()` 取全部客户无 DMA 过滤。
|
||||||
|
|
||||||
|
## 三、下线重构方案(分阶段)
|
||||||
|
|
||||||
|
### 阶段 0:立即可删(零调用方,已实证)
|
||||||
|
|
||||||
|
| 删除项 | 前置条件 |
|
||||||
|
|---|---|
|
||||||
|
| `RealtimePnlCalc.CalcDMAMargin()` + `CalculateMarginRequest.cs` + appsettings `CalculateDMAMarginUrl` 键 | 无 |
|
||||||
|
| `EodCheckMonitoredTrade.cs:186` 注释修正(去掉"阶段三待切项"误导) | 随上条同提交 |
|
||||||
|
| `EodForwardMarginSettlement.cs` + `SettlementConfig.CalcForwradMargin` | 无(可选:同步清 `eod_forward_margin` 读方空转代码) |
|
||||||
|
|
||||||
|
### 阶段 1:小改造后可删(V1 模板链)
|
||||||
|
|
||||||
|
1. `tradeController.GetMarginTemplates/GetMarginTemplateItems` 改为从 `margin_template_v2` 取数(或确认 5 个页面的 V1 下拉已无业务意义直接去掉下拉)。
|
||||||
|
2. 改造完成后删:`margin_templateController.cs`、`Views/margin_template/*`、`MarginTemplateService.cs`、`margin_templateReq.cs`、`DBModels/margin_template.cs`、`YLContext.cs` 中对应 DbSet。
|
||||||
|
3. 远期导入的 V1 比率消费随阶段 2 远期业务结论一并处理。
|
||||||
|
|
||||||
|
### 阶段 2:需先迁移读链(client_marginrate / 远期)
|
||||||
|
|
||||||
|
1. 流水导入落快照(`SwapTradeFlowImportService.cs:351-393`)与录入取率回显(`GetInitMarginRate`)两条链迁 V2 引擎取率。
|
||||||
|
2. 迁完后整体下线 `MarginRateSwapController` + `MarginRateSwapService` + `client_marginrate` 表链,并清理 FunctionRight 残留权限。
|
||||||
|
3. 远期业务经业务确认后:无存量则 Forward 模块 + `MarginRate` 链整体清理;有存量则查询/平仓/对账页暂留、仅清结算死链。
|
||||||
|
|
||||||
|
### 需确认清单(删除前必须逐项闭环)
|
||||||
|
|
||||||
|
| 项 | 确认方式 | 风险 |
|
||||||
|
|---|---|---|
|
||||||
|
| Vue3 前端仓是否调用 `/trade/GetMarginTemplates`、ForwardTrade、MarginRateSwap 系列 action | 前端仓 grep(本仓不可见) | action 被直连调用 |
|
||||||
|
| trade 表有无远期存量数据、`sys_menu` 是否还挂远期菜单 | DB 查询 | 存量交易无法查询/平仓 |
|
||||||
|
| `client_margin_template` 历史行 `MarginTemplateId` 是否残留 V1 id | DB 查询 | join 不上会静默落到第三级默认 |
|
||||||
|
| `client_marginrate` 表是否有 V2 之外的人工维护依赖(运营流程) | 业务确认 | 导入链迁 V2 后仍有人改旧表 |
|
||||||
|
| bond-oms 内部是否有 `/marginAlgorithm/realTimeMarginCalc` 的其他触发方 | bond-oms 仓确认 | Java 端点下线 |
|
||||||
|
|
||||||
|
### 不可删清单(防误伤)
|
||||||
|
|
||||||
|
`client_margin_template` / `margin_template_detail` / `trade_margin_template`(V2 数据源)、`MarginParamProvider`(涨跌幅/波动率在用)、`Client.SwapTradeType` 及其 2 处分支、`ClientBalanceTask`、`SwapFlowCombookingHub`。
|
||||||
|
|
||||||
|
### 顺手项(命名去毒,不动逻辑)
|
||||||
|
|
||||||
|
- `ClientNoDMABalanceTask` 任务名、`SwapFlowCombookingHub` "DMA合成持仓" region 名、`ClientBalanceForTrsResponse.ClientType` 注释口径,均与实际行为不符,可在触碰时改名。
|
||||||
|
|
||||||
|
## 四、验证纪律(执行删除时)
|
||||||
|
|
||||||
|
沿用 2026-08 死代码清理的教训(见 `多租户死代码清理执行计划.md`):
|
||||||
|
1. 每个删除项独立小提交,删前全文件类型 grep(不止 *.cs,含 js/cshtml/xml/json/配置),删后 Release + Debug 双构建;
|
||||||
|
2. `git rm` 目录混批后必须重新 find 核对(笔误会静默回滚整批);
|
||||||
|
3. 涉及 DBModel/列的删除,列残留留给 DBA,不在应用层迁移;
|
||||||
|
4. action 删除必须先过"前端仓确认"关卡。
|
||||||
Reference in New Issue
Block a user