Skip to content

Commit a83820b

Browse files
committed
Samples
1 parent 9b8bd51 commit a83820b

3 files changed

Lines changed: 103 additions & 45 deletions

File tree

Dashboard/Dashboard/Pages/Options/BreakProtection.razor

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
<ControlsComponent Adapters="Adapters">
66
<ChartsComponent Name="Prices" @ref="DataView" />
7-
<ChartsComponent Name="Delta" @ref="DeltaView" />
8-
<ChartsComponent Name="Variance" @ref="VarianceView" />
97
<ChartsComponent Name="Performance" @ref="PerformanceView" />
108
<OrdersComponent Name="Orders" @ref="OrdersView" />
119
<PositionsComponent Name="Positions" @ref="PositionsView" />

Dashboard/Dashboard/Pages/Options/BreakProtection.razor.cs

Lines changed: 57 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -17,27 +17,28 @@ namespace Dashboard.Pages.Options
1717
{
1818
public partial class BreakProtection
1919
{
20+
static double IV { get; set; } = 0.15;
21+
static double DivRate { get; set; } = 0.05;
22+
static double RiskRate { get; set; } = 0.05;
23+
double? Strike { get; set; }
24+
double? StrikeUp { get; set; }
25+
double? StrikeDown { get; set; }
26+
OptionSideEnum? Side { get; set; }
27+
2028
ControlsComponent View { get; set; }
2129
ChartsComponent DataView { get; set; }
22-
ChartsComponent DeltaView { get; set; }
23-
ChartsComponent VarianceView { get; set; }
2430
ChartsComponent PerformanceView { get; set; }
2531
TransactionsComponent TransactionsView { get; set; }
2632
OrdersComponent OrdersView { get; set; }
2733
PositionsComponent PositionsView { get; set; }
2834
StatementsComponent StatementsView { get; set; }
2935
PerformanceIndicator Performance { get; set; }
30-
OptionPriceService PriceService { get; set; } = new(0.05, 0.05, 0.15);
36+
OptionPriceService PriceService { get; set; } = new(RiskRate, DivRate, IV);
3137
Dictionary<string, Instrument> Instruments => new()
3238
{
3339
["SPY"] = new Instrument { Name = "SPY", TimeFrame = TimeSpan.FromMinutes(1) }
3440
};
3541

36-
double? Strike { get; set; }
37-
double? StrikeUp { get; set; }
38-
double? StrikeDown { get; set; }
39-
OptionSideEnum? Side { get; set; }
40-
4142
DateTime CurDate(Price point)
4243
{
4344
var date = new DateTime(point.Time.Value);
@@ -72,13 +73,9 @@ IList<Order> Positions(IList<Order> positions, DateTime? date) => [.. positions
7273
protected override async Task OnView()
7374
{
7475
await DataView.Create("Data");
75-
await DeltaView.Create("Delta");
76-
await VarianceView.Create("Variance");
7776
await PerformanceView.Create("Performance");
7877

7978
DataView.Composers.ForEach(o => o.ShowIndex = i => GetDate(o.Items, (int)i));
80-
DeltaView.Composers.ForEach(o => o.ShowIndex = i => GetDate(o.Items, (int)i));
81-
VarianceView.Composers.ForEach(o => o.ShowIndex = i => GetDate(o.Items, (int)i));
8279
PerformanceView.Composers.ForEach(o => o.ShowIndex = i => GetDate(o.Items, (int)i));
8380
}
8481

@@ -88,7 +85,7 @@ protected override Task OnTrade()
8885
Adapter = new SimGateway
8986
{
9087
Connector = Connector,
91-
Source = "D:/Code/Options", // Configuration["Documents:Resources"],
88+
Source = Configuration["Documents:Resources"],
9289
Account = new()
9390
{
9491
Descriptor = "Demo",
@@ -107,17 +104,13 @@ protected override async void OnViewUpdate(Instrument instrument)
107104
var account = adapter.Account;
108105
var positions = (await adapter.GetPositions(default)).Data;
109106
var performance = await Performance.Update(Adapters.Values);
110-
var (curDelta, nextDelta, sigma) = GetIndicators(positions, price);
111107

112108
OrdersView.Update(Adapters.Values);
113109
PositionsView.Update(Adapters.Values);
114110
TransactionsView.Update(Adapters.Values);
115111
DataView.Update(price.Bar.Time.Value, "Data", "Bars", DataView.GetShape<CandleShape>(price));
116112
PerformanceView.Update(price.Time.Value, "Performance", "Balance", new AreaShape { Y = account.Balance + account.Performance });
117113
PerformanceView.Update(price.Time.Value, "Performance", "PnL", PerformanceView.GetShape<LineShape>(performance.Response, SKColors.OrangeRed));
118-
DeltaView.Update(price.Time.Value, "Delta", "Next Delta", new BarShape { Y = nextDelta, Component = ComUp });
119-
DeltaView.Update(price.Time.Value, "Delta", "Current Delta", new LineShape { Y = curDelta, Component = ComDown });
120-
VarianceView.Update(price.Time.Value, "Variance", "Sigma", new AreaShape { Y = sigma, Component = Com });
121114
}
122115

123116
protected override async Task OnTradeUpdate(Instrument instrument)
@@ -144,18 +137,24 @@ protected override async Task OnTradeUpdate(Instrument instrument)
144137
if (orders.Count is 0 && curPositions.Count == 4)
145138
{
146139
var options = await GetOptions(instrument, nextDate);
147-
var (curDelta, nextDelta, sigma) = GetIndicators(positions, point);
148140
var isBuy = price > Strike && Side is OptionSideEnum.Put;
149141
var isSell = price < Strike && Side is OptionSideEnum.Call;
150-
142+
var range = Range(price, IV);
143+
var contracts = nextPositions.Where(o => o.Side is OrderSideEnum.Long).Sum(o => o.Operation.Amount) / 2;
144+
var step = contracts is 0 ? 0.1 : Math.Max(0.1, (range / contracts).Value);
145+
151146
if (nextPositions.Count is 0 || isBuy || isSell)
152147
{
153-
var order = GetNextOrder(options, isSell ? -1 : 1);
154-
await adapter.SendOrder(order);
155-
Side = isSell ? OptionSideEnum.Put : OptionSideEnum.Call;
148+
var order = GetNextOrder(options, isSell ? -1 : 1, nextPositions);
149+
150+
if (order is not null)
151+
{
152+
await adapter.SendOrder(order);
153+
Side = isSell ? OptionSideEnum.Put : OptionSideEnum.Call;
154+
}
156155
}
157156

158-
if (price - StrikeUp > 0.1)
157+
if (price - StrikeUp > step)
159158
{
160159
var order = GetCoverOrder(options, 1, price, nextPositions);
161160

@@ -166,7 +165,7 @@ protected override async Task OnTradeUpdate(Instrument instrument)
166165
}
167166
}
168167

169-
if (StrikeDown - price > 0.1)
168+
if (StrikeDown - price > step)
170169
{
171170
var order = GetCoverOrder(options, -1, price, nextPositions);
172171

@@ -237,29 +236,42 @@ async Task<IList<Instrument>> GetOptions(Instrument instrument, DateTime date)
237236
/// </summary>
238237
/// <param name="options"></param>
239238
/// <param name="direction"></param>
240-
Order GetNextOrder(IList<Instrument> options, int direction)
239+
Order GetNextOrder(IList<Instrument> options, int direction, IList<Order> positions)
241240
{
241+
var countLongs = positions
242+
.Where(o => o.Side is OrderSideEnum.Long)
243+
.Where(o => o.Operation.Instrument.Derivative.Side is OptionSideEnum.Call)
244+
.Sum(o => o.Operation.Amount);
245+
246+
var countShorts = positions
247+
.Where(o => o.Side is OrderSideEnum.Long)
248+
.Where(o => o.Operation.Instrument.Derivative.Side is OptionSideEnum.Put)
249+
.Sum(o => o.Operation.Amount);
250+
251+
var noLong = direction > 0 && countLongs > countShorts;
252+
var noShort = direction < 0 && countLongs < countShorts;
253+
254+
if (noLong || noShort)
255+
{
256+
return null;
257+
}
258+
242259
var instrument = null as Instrument;
243260

244261
if (direction < 0)
245262
{
246263
instrument = options
247264
?.Where(o => o.Derivative.Side is OptionSideEnum.Put)
248-
?.Where(o => o.Derivative.Strike <= Strike)
249-
?.LastOrDefault();
265+
?.Where(o => o.Derivative.Strike > Strike)
266+
?.FirstOrDefault();
250267
}
251268

252269
if (direction > 0)
253270
{
254271
instrument = options
255272
?.Where(o => o.Derivative.Side is OptionSideEnum.Call)
256-
?.Where(o => o.Derivative.Strike >= Strike)
257-
?.FirstOrDefault();
258-
}
259-
260-
if (instrument is null)
261-
{
262-
return null;
273+
?.Where(o => o.Derivative.Strike < Strike)
274+
?.LastOrDefault();
263275
}
264276

265277
var order = new Order
@@ -281,21 +293,21 @@ Order GetNextOrder(IList<Instrument> options, int direction)
281293
Order GetCoverOrder(IList<Instrument> options, int direction, double? price, IList<Order> positions)
282294
{
283295
var instrument = null as Instrument;
284-
var longAmount = positions
296+
var countLongs = positions
285297
.Where(o => o.Side is OrderSideEnum.Long)
286298
.Where(o => direction < 0 ?
287299
o.Operation.Instrument.Derivative.Side is OptionSideEnum.Put :
288300
o.Operation.Instrument.Derivative.Side is OptionSideEnum.Call)
289-
.Sum(o => o.Operation.Amount) - 1;
301+
.Sum(o => o.Operation.Amount);
290302

291-
var shortAmount = positions
303+
var countShorts = positions
292304
.Where(o => o.Side is OrderSideEnum.Short)
293305
.Where(o => direction < 0 ?
294306
o.Operation.Instrument.Derivative.Side is OptionSideEnum.Put :
295307
o.Operation.Instrument.Derivative.Side is OptionSideEnum.Call)
296308
.Sum(o => o.Operation.Amount);
297309

298-
if (longAmount - shortAmount < 1)
310+
if (countLongs - countShorts <= 1)
299311
{
300312
return null;
301313
}
@@ -316,11 +328,6 @@ Order GetCoverOrder(IList<Instrument> options, int direction, double? price, ILi
316328
?.FirstOrDefault();
317329
}
318330

319-
if (instrument is null)
320-
{
321-
return null;
322-
}
323-
324331
var order = new Order
325332
{
326333
Side = OrderSideEnum.Short,
@@ -401,5 +408,12 @@ Order GetCurOrder(IList<Instrument> options)
401408

402409
return order;
403410
}
411+
412+
/// <summary>
413+
/// Expected daily variance
414+
/// </summary>
415+
/// <param name="price"></param>
416+
/// <param name="volatility"></param>
417+
double? Range(double? price, double? volatility) => Math.Sqrt(1.0 / 252.0) * price * volatility;
404418
}
405419
}

Dashboard/Dashboard/Services/OptionPriceService.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
namespace Dashboard.Services
22
{
3+
using Core.Enums;
4+
using Estimator.Services;
35
using QuantLib;
6+
using System;
47

58
public class OptionPriceService
69
{
@@ -20,6 +23,8 @@ public class OptionPriceService
2023
private readonly YieldTermStructureHandle dividendHandle;
2124
private readonly BlackVolTermStructureHandle volHandle;
2225

26+
private readonly OptionService optionService = new();
27+
2328
public OptionPriceService(double riskFreeRate, double dividendRate, double volatility)
2429
{
2530
settings.setEvaluationDate(evaluationDate);
@@ -42,6 +47,13 @@ public OptionPriceService(double riskFreeRate, double dividendRate, double volat
4247
engine = new AnalyticEuropeanEngine(process);
4348
}
4449

50+
/// <summary>
51+
/// Estimated delta
52+
/// </summary>
53+
/// <param name="optionType"></param>
54+
/// <param name="spotPrice"></param>
55+
/// <param name="strikePrice"></param>
56+
/// <param name="timeToMaturity"></param>
4557
public double Delta(Option.Type optionType, double? spotPrice, double? strikePrice, double timeToMaturity)
4658
{
4759
spotQuote.setValue(spotPrice.Value);
@@ -56,6 +68,14 @@ public double Delta(Option.Type optionType, double? spotPrice, double? strikePri
5668
return option.delta();
5769
}
5870

71+
/// <summary>
72+
/// Estimated volatility
73+
/// </summary>
74+
/// <param name="optionPrice"></param>
75+
/// <param name="spotPrice"></param>
76+
/// <param name="strikePrice"></param>
77+
/// <param name="timeToMaturity"></param>
78+
/// <param name="optionType"></param>
5979
public double Sigma(double optionPrice, double spotPrice, double strikePrice, double timeToMaturity, Option.Type optionType)
6080
{
6181
spotQuote.setValue(spotPrice);
@@ -76,5 +96,31 @@ public double Sigma(double optionPrice, double spotPrice, double strikePrice, do
7696
5.0 // max vol guess
7797
);
7898
}
99+
100+
/// <summary>
101+
/// Estimated price
102+
/// </summary>
103+
/// <param name="optionType"></param>
104+
/// <param name="spotPrice"></param>
105+
/// <param name="strikePrice"></param>
106+
/// <param name="timeToMaturity"></param>
107+
/// <param name="volatility"></param>
108+
/// <param name="riskRate"></param>
109+
/// <param name="divRate"></param>
110+
public double Price(
111+
string optionType,
112+
double spotPrice,
113+
double strikePrice,
114+
double timeToMaturity,
115+
double volatility,
116+
double riskRate = 0.05,
117+
double divRate = 0.05) => OptionService.Price(
118+
optionType,
119+
spotPrice,
120+
strikePrice,
121+
timeToMaturity,
122+
volatility,
123+
riskRate,
124+
divRate);
79125
}
80126
}

0 commit comments

Comments
 (0)