Skip to content

Commit

Permalink
Add Fd1d_BlackScholes_Pricer
Browse files Browse the repository at this point in the history
  • Loading branch information
gituliar committed Feb 29, 2024
1 parent 2f0bec0 commit fcba3a2
Show file tree
Hide file tree
Showing 11 changed files with 150 additions and 53 deletions.
4 changes: 3 additions & 1 deletion .vs/launch.vs.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
"currentDir": "${workspaceRoot}",
"args": [
"price",
"test/portfolio_42k.csv"
"--density 0.1",
"--scale 1",
"test/portfolio_qdfp.csv"
]
}
]
Expand Down
22 changes: 4 additions & 18 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,22 +1,8 @@
bench:
out/linux-release/src/kwinto bench test/portfolio.csv -v --cpu32 --cpu64 --gpu32 --gpu64 -n 8 -b 128 -x 512 -t 512 | tee log/`hostname`_512_128.log
out/linux-release/src/kwinto bench test/portfolio.csv -v --cpu32 --cpu64 --gpu32 --gpu64 -n 8 -b 256 -x 512 -t 512 | tee log/`hostname`_512_256.log
out/linux-release/src/kwinto bench test/portfolio.csv -v --cpu32 --cpu64 --gpu32 --gpu64 -n 8 -b 512 -x 512 -t 512 | tee log/`hostname`_512_512.log
out/linux-release/src/kwinto bench test/portfolio.csv -v --cpu32 --cpu64 --gpu32 --gpu64 -n 8 -b 1024 -x 512 -t 512 | tee log/`hostname`_512_1024.log
out/linux-release/src/kwinto bench test/portfolio.csv -v --cpu32 --cpu64 --gpu32 --gpu64 -n 8 -b 2048 -x 512 -t 512 | tee log/`hostname`_512_2048.log
out/linux-release/src/kwinto bench test/portfolio.csv -v --cpu32 --cpu64 --gpu32 --gpu64 -n 8 -b 4096 -x 512 -t 512 | tee log/`hostname`_512_4096.log
out/linux-release/src/kwinto bench test/portfolio.csv -v --cpu32 --cpu64 --gpu32 --gpu64 -n 8 -b 8192 -x 512 -t 512 | tee log/`hostname`_512_8192.log
out/linux-release/src/kwinto bench test/portfolio.csv -v --cpu32 --cpu64 --gpu32 --gpu64 -n 8 -b 16384 -x 512 -t 512 | tee log/`hostname`_512_16384.log
out/linux-release/src/kwinto bench test/portfolio.csv -v --cpu32 --cpu64 --gpu32 --gpu64 -n 4 -b 32768 -x 512 -t 512 | tee log/`hostname`_512_32768.log
out/linux-release/src/kwinto bench test/portfolio.csv -v --cpu32 --cpu64 --gpu32 --gpu64 -n 8 -b 128 -x 1024 -t 1024 | tee log/`hostname`_1024_128.log
out/linux-release/src/kwinto bench test/portfolio.csv -v --cpu32 --cpu64 --gpu32 --gpu64 -n 8 -b 256 -x 1024 -t 1024 | tee log/`hostname`_1024_256.log
out/linux-release/src/kwinto bench test/portfolio.csv -v --cpu32 --cpu64 --gpu32 --gpu64 -n 8 -b 512 -x 1024 -t 1024 | tee log/`hostname`_1024_512.log
out/linux-release/src/kwinto bench test/portfolio.csv -v --cpu32 --cpu64 --gpu32 --gpu64 -n 8 -b 1024 -x 1024 -t 1024 | tee log/`hostname`_1024_1024.log
out/linux-release/src/kwinto bench test/portfolio.csv -v --cpu32 --cpu64 --gpu32 --gpu64 -n 8 -b 2048 -x 1024 -t 1024 | tee log/`hostname`_1024_2048.log
out/linux-release/src/kwinto bench test/portfolio.csv -v --cpu32 --cpu64 --gpu32 --gpu64 -n 8 -b 4096 -x 1024 -t 1024 | tee log/`hostname`_1024_4096.log
out/linux-release/src/kwinto bench test/portfolio.csv -v --cpu32 --cpu64 --gpu32 --gpu64 -n 8 -b 8192 -x 1024 -t 1024 | tee log/`hostname`_1024_8192.log
out/linux-release/src/kwinto bench test/portfolio.csv -v --cpu32 --cpu64 --gpu32 --gpu64 -n 8 -b 16384 -x 1024 -t 1024 | tee log/`hostname`_1024_16384.log
out/linux-release/src/kwinto bench test/portfolio.csv -v --cpu32 --cpu64 --gpu32 --gpu64 -n 4 -b 32768 -x 1024 -t 1024 | tee log/`hostname`_1024_32768.log
out/linux-release/src/kwinto price -p FD1D-BS --density 0.30 --scale 50 test/portfolio_qdfp.csv
out/linux-release/src/kwinto price -p FD1D-BS --density 0.35 --scale 50 test/portfolio_qdfp.csv
out/linux-release/src/kwinto price -p FD1D-BS --density 0.40 --scale 50 test/portfolio_qdfp.csv
#out/linux-release/src/kwinto bench test/portfolio.csv -v --cpu32 --cpu64 --gpu32 --gpu64 -n 8 -b 8192 -x 512 -t 512 | tee log/`hostname`_512_8192.log


release: config build check
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ add_library(
"Math/kwMath.cpp"
"Pricer/kwBlackScholes.cpp"
"Pricer/kwFd1d.cpp"
"Pricer/kwFd1d_BlackScholes.cpp"
"Utils/kwPortfolio.cpp"

"kwVersion.cpp"
Expand Down
23 changes: 23 additions & 0 deletions src/Pricer/kwF1d1_BlackScholes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

#include "Pricer/kwBlackScholes.h"
#include "Pricer/kwFd1d.h"


namespace kw {

class Fd1d_BlackScholes_Pricer : public Pricer
{
private:
BlackScholes_Pricer
m_bs;
Fd1d_Pricer
m_fd1d;

public:
Error
init(const Config& config) final;
Error
price(const vector<Option>& assets, vector<f64>& prices) final;
};
}
16 changes: 8 additions & 8 deletions src/Pricer/kwFd1d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ using namespace kw;
Error
Fd1d_Pricer::init(const Config& config)
{
m_density = config.get("FD1D.DENSITY", 0.25);
m_scale = config.get("FD1D.SCALE", 50.);

m_tDim = config.get("FD1D.T_GRID_SIZE", 512);
m_xDim = config.get("FD1D.X_GRID_SIZE", 512);

Expand Down Expand Up @@ -107,20 +110,17 @@ Fd1d_Pricer::price(const vector<Option>& assets, vector<f64>& prices)
for (auto i = 0; i < m; ++i) {
const auto& asset = assets[pde2asset[i]];

const f64 density = 0.5;
const f64 scale = 50;

const f64 xMid = 0.; // log(asset.s / asset.k);
const f64 xMin = xMid - scale * asset.z * sqrt(asset.t);
const f64 xMax = xMid + scale * asset.z * sqrt(asset.t);
const f64 xMin = xMid - m_scale * asset.z * sqrt(asset.t);
const f64 xMax = xMid + m_scale * asset.z * sqrt(asset.t);

const f64 yMin = asinh((xMin - xMid) / density);
const f64 yMax = asinh((xMax - xMid) / density);
const f64 yMin = asinh((xMin - xMid) / m_density);
const f64 yMax = asinh((xMax - xMid) / m_density);

const f64 dy = 1. / (m_xDim - 1);
for (auto j = 0; j < m_xDim; ++j) {
const f64 yj = j * dy;
m_x(i, j) = xMid + density * sinh(yMin * (1.0 - yj) + yMax * yj);
m_x(i, j) = xMid + m_density * sinh(yMin * (1.0 - yj) + yMax * yj);
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/Pricer/kwFd1d.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
namespace kw
{

///
/// 𝒜 = -r + (r - z²/2) 𝒟x + z²/2 𝒟xx
///
class Fd1d_Pricer : public Pricer
{
private:
f64 m_density;
f64 m_scale;
u64 m_tDim;
u64 m_xDim;

Expand Down
43 changes: 43 additions & 0 deletions src/Pricer/kwFd1d_BlackScholes.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include "Pricer/kwF1d1_BlackScholes.h"

using namespace kw;


Error
Fd1d_BlackScholes_Pricer::init(const Config& config)
{
if (auto err = m_fd1d.init(config); !err.empty())
return "Fd1d_BlackScholes_Pricer::init : " + err;

return "";
}

Error
Fd1d_BlackScholes_Pricer::price(const vector<Option>& assets, vector<f64>& prices)
{
if (auto err = m_fd1d.price(assets, prices); !err.empty())
return "Fd1d_BlackScholes_Pricer::price : " + err;

auto assets_ = assets;
for (auto& asset : assets_)
asset.e = false;

vector<f64> pricesFd1d;
pricesFd1d.resize(prices.size());
if (auto err = m_fd1d.price(assets_, pricesFd1d); !err.empty())
return "Fd1d_BlackScholes_Pricer::price : " + err;

vector<f64> pricesBs;
pricesBs.resize(prices.size());

BlackScholes_Pricer bs;
if (auto err = m_bs.price(assets_, pricesBs); !err.empty())
return "Fd1d_BlackScholes_Pricer::price : " + err;


for (auto i = 0; i < prices.size(); i++) {
prices[i] += pricesBs[i] - pricesFd1d[i];
}

return "";
}
27 changes: 15 additions & 12 deletions src/Pricer/kwPricerFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "Core/kwConfig.h"
#include "Pricer/kwBlackScholes.h"
#include "Pricer/kwFd1d.h"
#include "Pricer/kwF1d1_BlackScholes.h"


namespace kw
Expand All @@ -18,23 +19,25 @@ class PricerFactory
if (mode.empty())
return "PricerFactory: Missing PRICER key";

if (mode == "BS")
{
if (mode == "BS") {
pricer = make_sPtr<BlackScholes_Pricer>();
if (auto error = pricer->init(config); !error.empty())
return "PricerFactory: " + error;
return "";
if (auto err = pricer->init(config); !err.empty())
return "PricerFactory: " + err;
}

if (mode == "FD1D")
{
else if (mode == "FD1D") {
pricer = make_sPtr<Fd1d_Pricer>();
if (auto error = pricer->init(config); !error.empty())
return "PricerFactory: " + error;
return "";
if (auto err = pricer->init(config); !err.empty())
return "PricerFactory: " + err;
}
else if (mode == "FD1D-BS") {
pricer = make_sPtr<Fd1d_BlackScholes_Pricer>();
if (auto err = pricer->init(config); !err.empty())
return "PricerFactory: " + err;
}
else
return "PricerFactory: Unknown PRICER = " + mode;

return "PricerFactory: Unknown PRICER = " + mode;
return "";
}
};

Expand Down
21 changes: 17 additions & 4 deletions src/kwinto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ kwinto - Options Pricing Analytics
<path> CSV file with options data
Options:
--density <num> Density of the x-grid distribution [default: 0.25]
--scale <num> Scale of the x-grid distribution [default: 50.0]
-e <num> Reject option prices less than <num> from RRMS error stats [default: 0.5]
-n <num> Run <num> batches (when 0 run all) [default: 0]
-p <name> Pricer name [default: FD1D-BS]
-t <num> Use <num> points for t-grid [default: 512]
-x <num> Use <num> points for x-grid [default: 512]
-v Show extra details, be verbose
Expand All @@ -41,13 +43,24 @@ kw::Error
{
kw::Config config;

config.set("PRICER", "FD1D");
config.set("PRICER", args.at("-p").asString());

f64 density;
if (auto error = kw::fromString(args.at("--density").asString(), density); !error.empty())
return "cmdBench: Fail to parse '--density <num>': " + error;
config.set("FD1D.DENSITY", density);

f64 scale;
if (auto error = kw::fromString(args.at("--scale").asString(), scale); !error.empty())
return "cmdBench: Fail to parse '--scale <num>': " + error;
config.set("FD1D.SCALE", scale);

config.set("FD1D.T_GRID_SIZE", args.at("-t").asLong());
config.set("FD1D.X_GRID_SIZE", args.at("-x").asLong());

double tolerance;
f64 tolerance;
if (auto error = kw::fromString(args.at("-e").asString(), tolerance); !error.empty())
return "cmdBench: Fail to parse '-n <num>': " + error;
return "cmdBench: Fail to parse '-e <num>': " + error;

/// Load Portfolio
///
Expand Down
36 changes: 30 additions & 6 deletions test/kwPricer_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ class kwPricerTest : public testing::Test {
{{1.0, 100., 0.2, 0.06, 0.02, 100., 0, +1}, 9.729},
{{1.0, 100., 0.2, 0.06, 0.02, 110., 0, +1}, 16.633},

{{1.0, 100., 0.2, 0.06, 0.08, 90., 1, -1}, 13.988},
{{1.0, 100., 0.2, 0.06, 0.08, 100., 1, -1}, 8.409},
{{1.0, 100., 0.2, 0.06, 0.08, 110., 1, -1}, 4.659},
{{1.0, 100., 0.2, 0.06, 0.08, 90., 1, +1}, 2.947},
{{1.0, 100., 0.2, 0.06, 0.08, 100., 1, +1}, 6.842},
{{1.0, 100., 0.2, 0.06, 0.08, 110., 1, +1}, 12.794}
{{1.0, 100., 0.2, 0.06, 0.08, 90., 1, -1}, 13.988121682},
{{1.0, 100., 0.2, 0.06, 0.08, 100., 1, -1}, 8.409190396},
{{1.0, 100., 0.2, 0.06, 0.08, 110., 1, -1}, 4.6592955111},
{{1.0, 100., 0.2, 0.06, 0.08, 90., 1, +1}, 2.9472036256},
{{1.0, 100., 0.2, 0.06, 0.08, 100., 1, +1}, 6.8422540642},
{{1.0, 100., 0.2, 0.06, 0.08, 110., 1, +1}, 12.7940107108}
};
}

Expand Down Expand Up @@ -82,3 +82,27 @@ TEST_F(kwPricerTest, Fd1d)
EXPECT_NEAR(want, got, 1.3e-3);
}
}


TEST_F(kwPricerTest, Fd1dBlackScholes)
{
std::vector<Option> assets;
for (const auto& test : m_testData)
assets.push_back(test.first);

kw::Config config;
config.set("PRICER", "FD1D-BS");

kw::sPtr<kw::Pricer> pricer;
ASSERT_EQ(kw::PricerFactory::create(config, pricer), "");

std::vector<f64> prices;
ASSERT_EQ(pricer->price(assets, prices), "");

for (auto i = 0; i < m_testData.size(); ++i) {
const auto& want = m_testData[i].second;
const auto& got = prices[i];

EXPECT_NEAR(want, got, 1.3e-3);
}
}
6 changes: 3 additions & 3 deletions test/portfolio.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,14 +91,14 @@ def generate(fo, portfolio):
z = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5]

def to_string(x):
x_ = round(x, 6) + 0
return f'{x_:.6f}'.rstrip('0')
x_ = round(x, 12) + 0
return f'{x_:.12f}'.rstrip('0')

fo.write('expiry,spot,strike,volatility,interest_rate,dividend_rate,parity,exercise,price\n')
#fo.write('expiry,spot,strike,volatility,interest_rate,dividend_rate,parity,exercise,price,delta,gamma,vega,theta,rgo\n')
for option in product(t, s, k, z, r, q, w, e):
t, s, k, z, r, q, w, e = option
price_ = price(*option)
price_ = to_string(price(*option))
#price_ = to_string(price(*option))
#delta_ = to_string(delta(**kwargs))
#gamma_ = to_string(gamma(**kwargs))
Expand Down

0 comments on commit fcba3a2

Please sign in to comment.