Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
80e129b
Updated roadmap
aleCombi May 6, 2025
4798e72
first draft of my EnsembleSol with reuse of noiseproblem
aleCombi May 6, 2025
9991d9c
first sketch of fast noise solvers
aleCombi May 8, 2025
cf2ef63
Benchmarking speed up for montecarlo exact
aleCombi May 9, 2025
1658c8b
First quick solve with alloc
aleCombi May 9, 2025
c92f698
Best alloc free version so far
aleCombi May 9, 2025
1804ca6
Working on Montecarlo using marginal law for exact simulation and eur…
aleCombi May 15, 2025
ed07754
New way to do montecarlo sampling from Distributions.rand
aleCombi May 15, 2025
b2c01df
Seeding montecarlo sampler
aleCombi May 15, 2025
da1157c
Added license badge
aleCombi May 15, 2025
afd827c
Documenting montecarlo
aleCombi May 15, 2025
e626a24
Consolidated montecarlo european solvers
aleCombi Jul 9, 2025
f3ca176
Added docstrings
aleCombi Jul 9, 2025
fa23777
Moved heston to log space
aleCombi Jul 10, 2025
f41cfd5
Debugging heston exact
aleCombi Jul 11, 2025
c783e05
Correcting sampling of log_price for heston
aleCombi Jul 12, 2025
97a0986
Added heston montecarlo agreement tests and checks for seed numbers i…
aleCombi Jul 12, 2025
9817a86
Testing LSM against binomial tree
aleCombi Jul 12, 2025
fc1e8cc
Little corrections
aleCombi Jul 12, 2025
7fd8d8e
more euler heston paths
aleCombi Jul 12, 2025
ace54c1
Added montecarlo methods benchmark
aleCombi Jul 13, 2025
a166673
Removed old
aleCombi Jul 13, 2025
b79b93d
Trigger CI
aleCombi Jul 21, 2025
2d5d0ab
CI name change to allow PR checks succeeding
aleCombi Jul 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
name: CI

on:
push:
branches:
- master
tags: ['*']
pull_request:
workflow_dispatch:

concurrency:
# Skip intermediate builds: always.
# Cancel intermediate builds: only if it is a pull request build.
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}

jobs:
test:
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }}
name: CI
runs-on: ${{ matrix.os }}
timeout-minutes: 60
permissions: # needed to allow julia-actions/cache to proactively delete old caches that it has created
permissions:
actions: write
contents: read
strategy:
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

[![Build Status](https://github.com/aleCombi/Hedgehog.jl/actions/workflows/CI.yml/badge.svg?branch=master)](https://github.com/aleCombi/Hedgehog.jl/actions/workflows/CI.yml?query=branch%3Amaster)
[![Documentation](https://img.shields.io/badge/docs-stable-blue.svg)](https://alecombi.github.io/Hedgehog.jl/)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)

## 📐 Design Overview

Expand Down
6 changes: 4 additions & 2 deletions docs/src/derivatives_pricing_roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,11 @@
- [x] Ensure full test suite runs via `Pkg.test()`
- [x] CI: GitHub Actions with coverage and doc build
- [x] Tag `v0.1.0` and submit to Julia registry
- [ ] Soft launch: share with trusted peers, hold off on broad announcement
- [x] Soft launch: annunce on JuliaDiscourse

---
## PHASE 4.5 — Basic Jump support
- [ ] Merton model with Carr Madan
- [ ] Merton model with Montecarlo

## PHASE 5 — Structured Payoffs

Expand Down
3 changes: 3 additions & 0 deletions examples/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
DataInterpolations = "82cc6244-b520-54b8-b5a6-8a565e85f1d0"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
DiffEqNoiseProcess = "77a26b50-5914-5dd7-bc55-306e6241c503"
Distributions = "31c24e10-a181-5473-b8eb-7969acd0382f"
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
Hedgehog = "7f16798b-0e18-40de-98af-932948254698"
Expand All @@ -14,8 +15,10 @@ Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
Pluto = "c3e4b0f8-55cb-11ea-2926-15256bba5781"
PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
Polynomials = "f27b6e38-b328-58d1-80ce-0feddd5e7a45"
ProfileView = "c46f51b8-102a-5cf2-8d2c-8597cb0e0da7"
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
Roots = "f2b01f46-fcfa-551c-844a-d8ac1e96c665"
SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462"
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
StochasticDiffEq = "789caeaf-c7a9-5a7d-9973-96adeb23e2a0"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
54 changes: 54 additions & 0 deletions examples/mc_heston_euler.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Define the vanilla option payoff
strike = 100.0
expiry_date = Date(2025, 12, 31)
payoff = VanillaOption(strike, expiry_date, European(), Call(), Spot())

# Define the Heston model market inputs using positional arguments
reference_date = Date(2025, 1, 1)
spot = 100.0
rate = 0.05
heston_inputs = HestonInputs(
reference_date,
rate,
spot,
1.5, # kappa
0.04, # theta
0.3, # sigma
-0.6, # rho
0.04 # v0
)

# Create the pricing problem
problem = PricingProblem(payoff, heston_inputs)

# Generate a vector of seeds for reproducibility
num_paths = 10_000
rng = MersenneTwister(42)
seeds = rand(rng, UInt, num_paths)

# Pricing with Broadie-Kaya (Heston Exact) using Antithetic variance reduction
mc_exact_method = MonteCarlo(
HestonDynamics(),
HestonBroadieKaya(),
SimulationConfig(num_paths; seeds=seeds)
)
solution_exact = solve(problem, mc_exact_method)
price_exact = solution_exact.price

# Pricing with Euler-Maruyama using Antithetic variance reduction
mc_euler_method = MonteCarlo(
HestonDynamics(),
EulerMaruyama(),
SimulationConfig(10*num_paths; steps=200, seeds=seeds, variance_reduction=Hedgehog.Antithetic())
)
solution_euler = solve(problem, mc_euler_method)
sample_at_expiry = Hedgehog.get_final_samples(problem, mc_euler_method)
sde_prob = Hedgehog.sde_problem(problem, mc_euler_method)
ens = Hedgehog.simulate_paths(sde_prob, mc_euler_method, mc_euler_method.config.variance_reduction)

config = mc_euler_method.config
dt = sde_prob.tspan[2] / config.steps
ensemble_prob = Hedgehog.get_ensemble_problem(sde_prob, config)
normal_sol = StochasticDiffEq.solve(ensemble_prob, EM(); dt = dt, trajectories=config.trajectories)

price_euler = solution_euler.price
71 changes: 71 additions & 0 deletions examples/montecarlo_benchmark.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using Revise
using Hedgehog
using Dates
using Printf
using BenchmarkTools
using Random

function test_eur()
spot = 100.0
strike = 100.0
rate = 0.05
sigma = 0.20
reference_date = Date(2023, 1, 1)
expiry = reference_date + Year(1)

# Create the payoff (European call option)
payoff = VanillaOption(strike, expiry, European(), Call(), Spot())

# Create market inputs
market_inputs = BlackScholesInputs(reference_date, rate, spot, sigma)

# Create pricing problem
prob = PricingProblem(payoff, market_inputs)

trajectories = 5_000
mc_exact_method =
MonteCarlo(LognormalDynamics(), BlackScholesExact(), SimulationConfig(trajectories))
mc_exact_solution = solve(prob, mc_exact_method)
@show mc_exact_solution.price

display(@benchmark solve($prob, $mc_exact_method))
end

function test_am()
@show "american"
# Define market inputs
strike = 10.0
reference_date = Date(2020, 1, 1)
expiry = reference_date + Year(1)
rate = 0.05
spot = 10.0
sigma = 0.2
market_inputs = BlackScholesInputs(reference_date, rate, spot, sigma)

# Define payoff
american_payoff = VanillaOption(strike, expiry, American(), Put(), Spot())

# -- Wrap everything into a pricing problem
prob = PricingProblem(american_payoff, market_inputs)

# --- LSM using `solve(...)` style
dynamics = LognormalDynamics()
trajectories = 10_000
steps_lsm = 100

strategy = BlackScholesExact()
config = Hedgehog.SimulationConfig(trajectories; steps=steps_lsm, variance_reduction=Hedgehog.Antithetic()
#variance_reduction=Hedgehog.NoVarianceReduction()
)
degree = 5
lsm_method = LSM(dynamics, strategy, config, degree)

lsm_solution = Hedgehog.solve(prob, lsm_method)

@show lsm_solution.price

display(@benchmark Hedgehog.solve($prob, $lsm_method))
end

test_eur()
test_am()
48 changes: 48 additions & 0 deletions examples/montecarlo_exact.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using Revise, Hedgehog, BenchmarkTools, Dates
using Accessors
import Accessors: @optic
using StochasticDiffEq

# ------------------------------
# Define payoff and pricing problem
# ------------------------------
strike = 1.0
expiry = Date(2021, 1, 1)

euro_payoff = VanillaOption(strike, expiry, European(), Put(), Spot())

reference_date = Date(2020, 1, 1)
rate = 0.03
spot = 1.0
sigma = 0.04

market_inputs = BlackScholesInputs(reference_date, rate, spot, sigma)
euro_pricing_prob = PricingProblem(euro_payoff, market_inputs)

dynamics = LognormalDynamics()
trajectories = 10000
config = Hedgehog.SimulationConfig(trajectories; steps=100, variance_reduction=Hedgehog.Antithetic())
strategy = EulerMaruyama()
montecarlo_method = MonteCarlo(dynamics, strategy, config)

solution_analytic = Hedgehog.solve(euro_pricing_prob, BlackScholesAnalytic()).price
solution = Hedgehog.solve(euro_pricing_prob, montecarlo_method).price

@show Hedgehog.solve(euro_pricing_prob, montecarlo_method).price
@show Hedgehog.solve(euro_pricing_prob, BlackScholesAnalytic()).price

law = Hedgehog.marginal_law(euro_pricing_prob, LognormalDynamics(), expiry) #log-marginal law
log_sample = rand(law, trajectories)
final_sample = exp.(log_sample)
payoff_sample = euro_payoff.(final_sample)
discount = df(euro_pricing_prob.market_inputs.rate, euro_pricing_prob.payoff.expiry)
price = discount * mean(payoff_sample)

antithetic_sample = exp.(2 * mean(law) .- log_sample)
payoff_anti_sample = (euro_payoff.(final_sample) + euro_payoff.(antithetic_sample)) / 2
price_anti = discount * mean(payoff_anti_sample)

montecarlo_method_exact = MonteCarlo(dynamics, BlackScholesExact(), config)
solution_exact = Hedgehog.solve(euro_pricing_prob, montecarlo_method_exact).price
@btime Hedgehog.solve($euro_pricing_prob, $montecarlo_method_exact).price
@show solution_exact
Loading