Skip to content

Commit

Permalink
Option pricing
Browse files Browse the repository at this point in the history
  • Loading branch information
artemiusgreat committed Oct 8, 2024
1 parent 852e271 commit 49f1b72
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 21 deletions.
5 changes: 3 additions & 2 deletions Core/Enums/OptionSideEnum.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
namespace Terminal.Core.Enums
namespace Terminal.Core.Enums
{
public enum OptionSideEnum : byte
{
None = 0,
Put = 1,
Call = 2
Call = 2,
Share = 3
}
}
3 changes: 3 additions & 0 deletions Derivative/Models/OptionInputModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ public class OptionInputModel
[Required]
public double Premium { get; set; }

[Required]
public double Amount { get; set; }

[Required]
public DateTime? Date { get; set; }

Expand Down
6 changes: 5 additions & 1 deletion Derivative/Pages/Options.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,14 @@ public async Task Group(
IList<InstrumentModel> options,
Func<CanvasView, IList<InstrumentModel>, Task> action)
{
if (string.Equals(combine, "Yes"))
if (Groups.ContainsKey(caption) is false)
{
Groups[caption] = new Dictionary<string, CanvasView> { [caption] = null };
await InvokeAsync(StateHasChanged);
}

if (string.Equals(combine, "Yes"))
{
Groups[caption].ForEach(async o => await action(o.Value, options));
return;
}
Expand Down
2 changes: 2 additions & 0 deletions Derivative/Pages/Popups/OptionEditor.razor
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
<MudTextField Label="Price" Variant="Variant.Text" Margin="Margin.Dense" Class="mt-3" @bind-Value="InputModel.Price" For="@(() => InputModel.Price)"></MudTextField>
<MudTextField Label="Strike" Variant="Variant.Text" Margin="Margin.Dense" Class="mt-3" @bind-Value="InputModel.Strike" For="@(() => InputModel.Strike)"></MudTextField>
<MudTextField Label="Premium" Variant="Variant.Text" Margin="Margin.Dense" Class="mt-3" @bind-Value="InputModel.Premium" For="@(() => InputModel.Premium)"></MudTextField>
<MudTextField Label="Amount" Variant="Variant.Text" Margin="Margin.Dense" Class="mt-3" @bind-Value="InputModel.Amount" For="@(() => InputModel.Amount)"></MudTextField>
<MudSelect Label="Side" Variant="Variant.Text" Margin="Margin.Dense" Class="mt-3" @bind-Value="InputModel.Side" For="@(() => InputModel.Side)">
<MudSelectItem T="OptionSideEnum" Value="@(OptionSideEnum.Call)" />
<MudSelectItem T="OptionSideEnum" Value="@(OptionSideEnum.Put)" />
<MudSelectItem T="OptionSideEnum" Value="@(OptionSideEnum.Share)" />
</MudSelect>
<MudSelect Label="Direction" Variant="Variant.Text" Margin="Margin.Dense" Class="mt-3" @bind-Value="InputModel.Position" For="@(() => InputModel.Position)">
<MudSelectItem T="OrderSideEnum" Value="@(OrderSideEnum.Buy)" />
Expand Down
7 changes: 4 additions & 3 deletions Derivative/Pages/Popups/OptionEditor.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ public partial class OptionEditor : ComponentBase
protected OptionInputModel InputModel { get; set; } = new OptionInputModel
{
Name = "SPY",
Price = 100,
Strike = 110,
Premium = 0,
Price = 200,
Strike = 205,
Premium = 1.25,
Amount = 1,
Date = DateTime.Now.Date,
Side = OptionSideEnum.Call,
Position = OrderSideEnum.Buy
Expand Down
8 changes: 6 additions & 2 deletions Derivative/Pages/Portfolio.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,12 @@ public async Task OnCombine()
{
await OnChart<PortfolioEditor>(async (caption, response, items) =>
{
Groups[caption] = new Dictionary<string, CanvasView> { [caption] = null };
await InvokeAsync(StateHasChanged);
if (Groups.ContainsKey(caption) is false)
{
Groups[caption] = new Dictionary<string, CanvasView> { [caption] = null };
await InvokeAsync(StateHasChanged);
}

Groups[caption].ForEach(async o => await Show(o.Value, response, items));
});
}
Expand Down
48 changes: 35 additions & 13 deletions Derivative/Pages/Profile.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,15 @@
using Derivative.Models;
using Derivative.Pages.Popups;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Configuration;
using MudBlazor;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata.Ecma335;
using System.Threading.Tasks;
using Terminal.Core.Enums;
using Terminal.Core.Services;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace Derivative.Pages
{
Expand All @@ -25,6 +24,7 @@ public partial class Profile

protected int Count { get; set; } = 1;
protected bool IsLoading { get; set; }
protected Dictionary<double, double> Sums { get; set; } = [];
protected Dictionary<string, Dictionary<string, CanvasView>> Groups { get; set; } = [];

/// <summary>
Expand All @@ -44,8 +44,12 @@ public async Task OnCombine()
{
await OnChart<OptionEditor>(async (caption, response) =>
{
Groups[caption] = new Dictionary<string, CanvasView> { [caption] = null };
await InvokeAsync(StateHasChanged);
if (Groups.ContainsKey(caption) is false)
{
Groups[caption] = new Dictionary<string, CanvasView> { [caption] = null };
await InvokeAsync(StateHasChanged);
}

Groups[caption].ForEach(async o => await Show(o.Value, response));
});
}
Expand Down Expand Up @@ -79,7 +83,7 @@ protected async Task OnChart<T>(Func<string, OptionInputModel, Task> action) whe
var inputModel = response.Data as OptionInputModel;
var caption = $"{Count++} : {inputModel.Name}";

await action(caption, inputModel);
await action(inputModel.Name, inputModel);
}

IsLoading = false;
Expand All @@ -96,17 +100,19 @@ protected async Task OnChart<T>(Func<string, OptionInputModel, Task> action) whe
/// <returns></returns>
protected async Task Show(CanvasView view, OptionInputModel inputModel)
{
var min = Math.Min(inputModel.Price, inputModel.Strike);
var max = Math.Max(inputModel.Price, inputModel.Strike);
var prices = Enumerable.Range((int)(min - min / 2), (int)(max + max / 2));
var chartPoints = prices.Select((o, i) =>
var plusPercents = Enumerable.Range(0, 20).Select((o, i) => o / 2.0 / 100.0);
var minusPercents = Enumerable.Range(1, 20).Select((o, i) => -o / 2.0 / 100.0).Reverse();
var chartPoints = minusPercents.Concat(plusPercents).Select((o, i) =>
{
var direction = inputModel.Position is OrderSideEnum.Buy ? 1.0 : -1.0;
var step = inputModel.Price + inputModel.Price * o;
var sum = GetEstimate(step, inputModel);

Sums[o] = Sums.TryGetValue(o, out var s) ? s + sum : sum;

return new LineShape
{
X = i,
Y = (OptionService.Premium(inputModel.Side, i, inputModel.Strike, 0.000001, 0.25, 0.05, 0) - inputModel.Premium) * direction,
X = step,
Y = Sums[o],
Component = new ComponentModel { Size = 2, Color = SKColors.DeepSkyBlue }

} as IShape;
Expand All @@ -118,11 +124,27 @@ protected async Task Show(CanvasView view, OptionInputModel inputModel)
Space = 0.05,
Name = inputModel.Name,
Items = chartPoints,
View = view
View = view,
ShowIndex = o => $"{chartPoints.ElementAtOrDefault((int)o)?.X}"
};

await composer.Create<CanvasEngine>();
await composer.Update();
}

protected double GetEstimate(double price, OptionInputModel inputModel)
{
var direction = inputModel.Position is OrderSideEnum.Buy ? 1.0 : -1.0;

if (inputModel.Side is OptionSideEnum.Share)
{
return (price - inputModel.Price) * inputModel.Amount * direction;
}

var days = Math.Max((DateTime.Now - inputModel.Date).Value.TotalDays / 250.0, double.Epsilon);
var estimate = OptionService.Premium(inputModel.Side, price, inputModel.Strike, days, 0.25, 0.05, 0);

return (estimate - inputModel.Premium) * inputModel.Amount * direction * 100;
}
}
}

0 comments on commit 49f1b72

Please sign in to comment.