增加vega(1bp)希腊值

This commit is contained in:
尹峰
2026-08-20 14:15:12 +08:00
parent 30b3007307
commit 5ee510aa35
11 changed files with 110 additions and 18 deletions
@@ -0,0 +1,51 @@
using YLErp.Modules.CalculationModule;
using YLErp.Modules.EodModule;
namespace YLErp.BasicTests
{
[TestClass]
public class GLMSGreeksHandleServiceTest
{
[TestMethod]
public void Handle_NonRateAsset_CalculatesVega1bpBeforeRateFilter()
{
var service = new GLMSGreeksHandleService();
var dto = new EodPositionRisksDTO
{
Vega = 2500d
};
var underlying = new underlying_manager
{
UnderlyingInstrumentType = ConsGlobal.InstrumentType.Stock
};
service.Handle(dto, underlying);
Assert.IsNotNull(dto.Vega_1bp);
Assert.AreEqual(0.25d, dto.Vega_1bp.Value, 1e-12);
Assert.IsNull(dto.Vega_r);
Assert.IsNull(dto.Vega_r_1bp);
}
[TestMethod]
public void Handle_TradeValueResult_NonRateAsset_CalculatesVega1bpBeforeRateFilter()
{
var service = new GLMSGreeksHandleService();
var result = new TradeValueResult
{
Vega = 2500d
};
var underlying = new underlying_manager
{
UnderlyingInstrumentType = ConsGlobal.InstrumentType.Stock
};
service.Handle(new trade(), result, underlying);
Assert.IsNotNull(result.Vega_1bp);
Assert.AreEqual(0.25d, result.Vega_1bp.Value, 1e-12);
Assert.IsNull(result.Vega_r);
Assert.IsNull(result.Vega_r_1bp);
}
}
}
+2
View File
@@ -230,6 +230,8 @@ namespace YLErp.Model
public double? Vega_r_1bp { get; set; }
public double? Vega_1bp { get; set; }
/// <summary>
@@ -256,6 +256,7 @@ namespace YLErp.Modules.CalcPriceShowConfigModule
new CalcQuotaDto{Name="Gamma_r(1bp)",Tip=""},
new CalcQuotaDto{Name="Vega_r",Tip=""},
new CalcQuotaDto{Name="Vega_r(1bp)",Tip=""},
new CalcQuotaDto{Name="Vega(1bp)",Tip=""},
};
}
@@ -515,6 +515,8 @@ namespace YLErp.Modules.CalculationModule
public double? Vega_r { get; set; }
public double? Vega_r_1bp { get; set; }
public double? Vega_1bp { get; set; }
}
public class TradeValueResultExtend
@@ -2032,6 +2032,7 @@ namespace YLErp.Modules.EodModule
dic.Add("Gamma_r_1bp", OtcFormatExtensions.OtcFormat(item.Gamma_r_1bp, OtcFormatFlag.greek));
dic.Add("Vega_r", OtcFormatExtensions.OtcFormat(item.Vega_r, OtcFormatFlag.greek));
dic.Add("Vega_r_1bp", OtcFormatExtensions.OtcFormat(item.Vega_r_1bp, OtcFormatFlag.greek));
dic.Add("Vega_1bp", OtcFormatExtensions.OtcFormat(item.Vega_1bp, OtcFormatFlag.greek));
}
@@ -2143,6 +2144,7 @@ namespace YLErp.Modules.EodModule
dic.Add("Gamma_r_1bp", "");
dic.Add("Vega_r", "");
dic.Add("Vega_r_1bp", "");
dic.Add("Vega_1bp", "");
}
results.Add(dic);
}
@@ -164,6 +164,7 @@ namespace YLErp.Modules.EodModule
dto.Dv01 = calcDto.Dv01;
dto.Gamma_r_1bp = calcDto.Gamma_r_1bp;
dto.Vega_r_1bp = calcDto.Vega_r_1bp;
dto.Vega_1bp = calcDto.Vega_1bp;
}
@@ -183,6 +184,7 @@ namespace YLErp.Modules.EodModule
calRes.Dv01 = calcDto.Dv01;
calRes.Gamma_r_1bp = calcDto.Gamma_r_1bp;
calRes.Vega_r_1bp = calcDto.Vega_r_1bp;
calRes.Vega_1bp = calcDto.Vega_1bp;
}
@@ -267,6 +269,9 @@ namespace YLErp.Modules.EodModule
private void handle(GreeksCalcDto dto, underlying_manager um)
{
// 标准 Vega 的 1bp 变体:全资产计算,不受利率类过滤限制
dto.Vega_1bp = dto.Vega * 0.0001;
if (!calcInstrumentTypes.Contains(um.UnderlyingInstrumentType))
{
return;
@@ -353,6 +358,8 @@ namespace YLErp.Modules.EodModule
public double? Vega_r_1bp { get; set; }
public double? Vega_1bp { get; set; }
}
public class ChinaBondIndexQuoteQueryDto
+15 -8
View File
@@ -1195,59 +1195,66 @@
else if("Gamma*".Equals( quta.Name))
{
<tr>
<th title="Delta*">Gamma*</th>
<th title="Gamma*">Gamma*</th>
<td>{{calcResult.GammaContainsKnockOut}}</td>
</tr>
}
else if ("Delta_r".Equals(quta.Name))
{
<tr>
<th title="Delta*">Delta_r</th>
<th title="Delta_r">Delta_r</th>
<td>{{calcResult.Delta_r}}</td>
</tr>
}
else if ("Delta_r(1bp)".Equals(quta.Name))
{
<tr>
<th title="Delta*">Delta_r(1bp)</th>
<th title="Delta_r(1bp)">Delta_r(1bp)</th>
<td>{{calcResult.Delta_r_1bp}}</td>
</tr>
}
else if ("Dv01".Equals(quta.Name))
{
<tr>
<th title="Delta*">Dv01</th>
<th title="Dv01">Dv01</th>
<td>{{calcResult.Dv01}}</td>
</tr>
}
else if ("Gamma_r".Equals(quta.Name))
{
<tr>
<th title="Delta*">Gamma_r</th>
<th title="Gamma_r">Gamma_r</th>
<td>{{calcResult.Gamma_r}}</td>
</tr>
}
else if ("Gamma_r(1bp)".Equals(quta.Name))
{
<tr>
<th title="Delta*">Gamma_r(1bp)</th>
<th title="Gamma_r(1bp)">Gamma_r(1bp)</th>
<td>{{calcResult.Gamma_r_1bp}}</td>
</tr>
}
else if ("Vega_r".Equals(quta.Name))
{
<tr>
<th title="Delta*">Vega_r</th>
<th title="Vega_r">Vega_r</th>
<td>{{calcResult.Vega_r}}</td>
</tr>
}
else if ("Vega_r(1bp)".Equals(quta.Name))
{
<tr>
<th title="Delta*">Vega_r(1bp)</th>
<th title="Vega_r(1bp)">Vega_r(1bp)</th>
<td>{{calcResult.Vega_r_1bp}}</td>
</tr>
}
else if ("Vega(1bp)".Equals(quta.Name))
{
<tr>
<th title="Vega(1bp)">Vega(1bp)</th>
<td>{{calcResult.Vega_1bp}}</td>
</tr>
}
}
}
@@ -1,4 +1,4 @@
$(function () {
$(function () {
var __jq = {
PostData: typeof PostData !== 'undefined' ? PostData : {},
@@ -259,6 +259,13 @@ function ResetEditPanel(model) {
calcQuotaNameChecked.push(model.CalcQuota[i].Name);
}
}
// 编辑旧模板时,把模板未包含的新增指标(如 Vega(1bp))追加到勾选列表末尾,默认不勾选,保证与新增模板口径一致
var defaultQuota = pageObj && pageObj.DefaultQuota ? pageObj.DefaultQuota.CalcQuota : [];
for (var j = 0; j < defaultQuota.length; j++) {
if (!quotaOrder.includes(defaultQuota[j].Name)) {
quotaOrder.push(defaultQuota[j].Name);
}
}
InitQuotaCheckList(quotaOrder);
if (calcQuotaNameChecked != null && calcQuotaNameChecked.length > 0) {
@@ -559,6 +559,15 @@ function getColModelGrid() {
sortIndex: i++,
formatter: greeksFormat,
sortable: false
}, {
name: 'Vega_1bp',
label: 'Vega(1bp)',
index: 'Vega_1bp',
width: 100,
align: 'center',
sortIndex: i++,
formatter: greeksFormat,
sortable: false
},);
}
@@ -664,7 +673,7 @@ function TradeAmountFormat(cellValue, options, rowObject) {
}
function greeksFormat(cellValue, options, rowObject) {
if (cellValue) {
if (cellValue != null) {
return otcformat.trading.greek(cellValue);
}
return "";
@@ -214,7 +214,7 @@ const vueMarginTemplateName = function () {
}
//计算结果字段
const consCalcFields = Object.freeze(['TotalMargin', 'Pv', 'Delta', 'Gamma', 'Vega', 'Theta', 'Rho', 'PvContainsKnockOut', 'DeltaContainsKnockOut', 'DeltaInLots', 'GammaInLots', 'DeltaCash', 'GammaCash', 'VegaCash', 'GammaContainsKnockOut', 'Delta_r', 'Delta_r_1bp', 'Dv01', 'Gamma_r', 'Gamma_r_1bp', 'Vega_r', 'Vega_r_1bp']);
const consCalcFields = Object.freeze(['TotalMargin', 'Pv', 'Delta', 'Gamma', 'Vega', 'Theta', 'Rho', 'PvContainsKnockOut', 'DeltaContainsKnockOut', 'DeltaInLots', 'GammaInLots', 'DeltaCash', 'GammaCash', 'VegaCash', 'GammaContainsKnockOut', 'Delta_r', 'Delta_r_1bp', 'Dv01', 'Gamma_r', 'Gamma_r_1bp', 'Vega_r', 'Vega_r_1bp', 'Vega_1bp']);
var _trades, _tradeVues, _salesCommissionCtrl;
//交易保存
@@ -1913,13 +1913,14 @@ function createVue(index, baseVue, floating) {
calcResult.PvContainsKnockOut = pricingFormat.tradePrice(result.PvContainsKnockOut);
calcResult.DeltaContainsKnockOut = pricingFormat.greek(result.DeltaContainsKnockOut);
calcResult.GammaContainsKnockOut = pricingFormat.greek(result.GammaContainsKnockOut);
calcResult.Delta_r = result.Delta_r ? pricingFormat.greek(result.Delta_r) : "";
calcResult.Delta_r_1bp = result.Delta_r_1bp ? pricingFormat.greek(result.Delta_r_1bp) : "";
calcResult.Dv01 = result.Dv01 ? pricingFormat.greek(result.Dv01) : "";
calcResult.Gamma_r = result.Gamma_r ? pricingFormat.greek(result.Gamma_r) : "";
calcResult.Gamma_r_1bp = result.Gamma_r_1bp ? pricingFormat.greek(result.Gamma_r_1bp) : "";
calcResult.Vega_r = result.Vega_r ? pricingFormat.greek(result.Vega_r) : "";
calcResult.Vega_r_1bp = result.Vega_r_1bp ? pricingFormat.greek(result.Vega_r_1bp) : "";
calcResult.Delta_r = result.Delta_r != null ? pricingFormat.greek(result.Delta_r) : "";
calcResult.Delta_r_1bp = result.Delta_r_1bp != null ? pricingFormat.greek(result.Delta_r_1bp) : "";
calcResult.Dv01 = result.Dv01 != null ? pricingFormat.greek(result.Dv01) : "";
calcResult.Gamma_r = result.Gamma_r != null ? pricingFormat.greek(result.Gamma_r) : "";
calcResult.Gamma_r_1bp = result.Gamma_r_1bp != null ? pricingFormat.greek(result.Gamma_r_1bp) : "";
calcResult.Vega_r = result.Vega_r != null ? pricingFormat.greek(result.Vega_r) : "";
calcResult.Vega_r_1bp = result.Vega_r_1bp != null ? pricingFormat.greek(result.Vega_r_1bp) : "";
calcResult.Vega_1bp = result.Vega_1bp != null ? pricingFormat.greek(result.Vega_1bp) : "";
calcResult.TotalMargin = 0;
if (data === this.datas[this.datas.length - 1]) {
calcResult.TotalMargin = pageVue.GetTotalMargin(_.map(this.datas, x => x.trade), this.structureType);
@@ -245,6 +245,9 @@
<p>系统中 <span class="math notranslate nohighlight">\(𝜎_\mathrm{\bigtriangleup}\)</span> 为 0.5%</p>
</td>
</tr>
<tr class="row-odd"><td><p>Vega(1bp)</p></td>
<td><p><span class="math notranslate nohighlight">\(Vega(1bp) = Vega \times 0.0001\)</span>(标的波动率 σ 上升 1 个基点对应的价值变动)</p></td>
</tr>
<tr class="row-odd"><td><p>Theta</p></td>
<td><p>设当前期权到期时间为 <span class="math notranslate nohighlight">\(T\)</span>, 期权理论价值为 <span class="math notranslate nohighlight">\(V,T'=T-frac(1),\)</span></p>
<p>其中 <span class="math notranslate nohighlight">\(𝑓𝑟𝑎𝑐(1)\)</span> 是根据设定的日期规则计算一天的年化时间长度。例如:</p>