adding .NET and C++ receiver code
This commit is contained in:
parent
96c40481c0
commit
a730104083
.gitignoreCargo.lockCargo.toml
FinLib.NET
FinLib.Bench/Benchmarks
FinLib.Test
FinLib
finlib-cpp
finlib-ffi
finlib/src
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,7 @@
|
|||||||
/target
|
/target
|
||||||
bin
|
bin
|
||||||
obj
|
obj
|
||||||
|
cmake-build-debug
|
||||||
.venv
|
.venv
|
||||||
.idea
|
.idea
|
||||||
/finlib-wasm/pkg
|
/finlib-wasm/pkg
|
||||||
|
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -340,7 +340,7 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "finlib"
|
name = "finlib"
|
||||||
version = "0.0.6"
|
version = "0.0.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"criterion",
|
"criterion",
|
||||||
"getrandom 0.2.15",
|
"getrandom 0.2.15",
|
||||||
@ -357,7 +357,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "finlib-ffi"
|
name = "finlib-ffi"
|
||||||
version = "0.0.6"
|
version = "0.0.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cbindgen",
|
"cbindgen",
|
||||||
"csbindgen",
|
"csbindgen",
|
||||||
@ -366,7 +366,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "finlib-wasm"
|
name = "finlib-wasm"
|
||||||
version = "0.0.6"
|
version = "0.0.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console_error_panic_hook",
|
"console_error_panic_hook",
|
||||||
"console_log",
|
"console_log",
|
||||||
@ -759,7 +759,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyfinlib"
|
name = "pyfinlib"
|
||||||
version = "0.0.6"
|
version = "0.0.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"finlib",
|
"finlib",
|
||||||
"log",
|
"log",
|
||||||
|
@ -14,7 +14,7 @@ default-members = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.0.6"
|
version = "0.0.7"
|
||||||
authors = ["sarsoo <andy@sarsoo.xyz>"]
|
authors = ["sarsoo <andy@sarsoo.xyz>"]
|
||||||
description = "Quant finance functions implemented in Rust"
|
description = "Quant finance functions implemented in Rust"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
@ -30,5 +30,5 @@ public class HistoricalVar
|
|||||||
public double FinLibDotnet() => HistoricalVARDotnet.ValueAtRisk(data.ToList(), confidence);
|
public double FinLibDotnet() => HistoricalVARDotnet.ValueAtRisk(data.ToList(), confidence);
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public double FinLibRust() => FinLib.Risk.ValueAtRisk.Historical(data, confidence);
|
public double FinLibRust() => FinLib.Risk.ValueAtRisk.Historical(data, confidence)!.Value;
|
||||||
}
|
}
|
34
FinLib.NET/FinLib.Test/Portfolio.cs
Normal file
34
FinLib.NET/FinLib.Test/Portfolio.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
using FluentAssertions;
|
||||||
|
|
||||||
|
namespace FinLib.Test;
|
||||||
|
|
||||||
|
public class PortfolioTest
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestPortfolioCreation()
|
||||||
|
{
|
||||||
|
using var portfolio = new Portfolio();
|
||||||
|
portfolio.AddAsset(0.5, "first", [0.5, 0.5, 0.5, 0.5]);
|
||||||
|
portfolio.AddAsset(0.5, "second", [0.5, 0.5, 0.5, 0.5]);
|
||||||
|
|
||||||
|
var (mean, std) = portfolio.GetMeanAndStdDev()!.Value;
|
||||||
|
mean.Should().Be(0);
|
||||||
|
std.Should().Be(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPortfolioValid()
|
||||||
|
{
|
||||||
|
var portfolio = new Portfolio();
|
||||||
|
portfolio.AddAsset(0.5, "first", [0.5, 0.5, 0.5, 0.5]);
|
||||||
|
portfolio.AddAsset(0.5, "second", [0.5, 0.5, 0.5]);
|
||||||
|
|
||||||
|
portfolio.IsValid().Should().BeFalse();
|
||||||
|
|
||||||
|
var portfolio2 = new Portfolio();
|
||||||
|
portfolio2.AddAsset(0.5, "first", [0.5, 0.5, 0.5, 0.5]);
|
||||||
|
portfolio2.AddAsset(0.5, "second", [0.5, 0.5, 0.5, 0.5]);
|
||||||
|
|
||||||
|
portfolio2.IsValid().Should().BeTrue();
|
||||||
|
}
|
||||||
|
}
|
@ -7,26 +7,36 @@ namespace FinLib.Risk;
|
|||||||
|
|
||||||
public static class ValueAtRisk
|
public static class ValueAtRisk
|
||||||
{
|
{
|
||||||
public static double Historical(IEnumerable<double> values, double confidence)
|
public static double? Historical(IEnumerable<double> values, double confidence)
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
var valueArr = values.ToArray();
|
var valueArr = values.ToArray();
|
||||||
fixed (double* ptrOne = valueArr) {
|
fixed (double* ptrOne = valueArr) {
|
||||||
var ret = NativeMethods.historical_value_at_risk(ptrOne, (UIntPtr)valueArr.Length, confidence);
|
var ret = NativeMethods.historical_value_at_risk(ptrOne, (UIntPtr)valueArr.Length, confidence);
|
||||||
|
|
||||||
return *ret;
|
if (ret.is_valid)
|
||||||
|
{
|
||||||
|
return ret.val;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double VarCovar(IEnumerable<double> values, double confidence)
|
public static double? VarCovar(IEnumerable<double> values, double confidence)
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
var valueArr = values.ToArray();
|
var valueArr = values.ToArray();
|
||||||
fixed (double* ptrOne = valueArr) {
|
fixed (double* ptrOne = valueArr) {
|
||||||
var ret = NativeMethods.varcovar_value_at_risk(ptrOne, (UIntPtr)valueArr.Length, confidence);
|
var ret = NativeMethods.varcovar_value_at_risk(ptrOne, (UIntPtr)valueArr.Length, confidence);
|
||||||
|
|
||||||
return *ret;
|
if (ret.is_valid)
|
||||||
|
{
|
||||||
|
return ret.val;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,14 +16,12 @@ public static class Stats
|
|||||||
fixed (double* ptrTwo = valuesTwoArr) {
|
fixed (double* ptrTwo = valuesTwoArr) {
|
||||||
var ret = NativeMethods.covariance(ptrOne, (UIntPtr)valuesOneArr.Length, ptrTwo, (UIntPtr) valuesTwoArr.Length);
|
var ret = NativeMethods.covariance(ptrOne, (UIntPtr)valuesOneArr.Length, ptrTwo, (UIntPtr) valuesTwoArr.Length);
|
||||||
|
|
||||||
if (ret == null)
|
if (ret.is_valid)
|
||||||
{
|
{
|
||||||
return null;
|
return ret.val;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return *ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
using GroupedNativeMethodsGenerator;
|
|
||||||
|
|
||||||
namespace FinLib;
|
namespace FinLib;
|
||||||
|
|
||||||
[GroupedNativeMethods]
|
internal static partial class NativeMethods
|
||||||
internal static unsafe partial class NativeMethods
|
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
@ -20,56 +20,90 @@ namespace FinLib
|
|||||||
internal static extern double interest_compound(double principal, double rate, double time, double n);
|
internal static extern double interest_compound(double principal, double rate, double time, double n);
|
||||||
|
|
||||||
[DllImport(__DllName, EntryPoint = "covariance", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
[DllImport(__DllName, EntryPoint = "covariance", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||||
internal static extern double* covariance(double* arr, nuint len, double* arr_two, nuint len_two);
|
internal static extern NullableFloat covariance(double* arr, nuint len, double* arr_two, nuint len_two);
|
||||||
|
|
||||||
[DllImport(__DllName, EntryPoint = "historical_value_at_risk", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
[DllImport(__DllName, EntryPoint = "historical_value_at_risk", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||||
internal static extern double* historical_value_at_risk(double* arr, nuint len, double confidence);
|
internal static extern NullableFloat historical_value_at_risk(double* arr, nuint len, double confidence);
|
||||||
|
|
||||||
[DllImport(__DllName, EntryPoint = "varcovar_value_at_risk", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
[DllImport(__DllName, EntryPoint = "varcovar_value_at_risk", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||||
internal static extern double* varcovar_value_at_risk(double* arr, nuint len, double confidence);
|
internal static extern NullableFloat varcovar_value_at_risk(double* arr, nuint len, double confidence);
|
||||||
|
|
||||||
[DllImport(__DllName, EntryPoint = "scale_value_at_risk", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
[DllImport(__DllName, EntryPoint = "scale_value_at_risk", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||||
internal static extern double scale_value_at_risk(double initial_value, nint time_cycles);
|
internal static extern double scale_value_at_risk(double initial_value, nint time_cycles);
|
||||||
|
|
||||||
|
[DllImport(__DllName, EntryPoint = "portfolio_asset_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||||
|
internal static extern PortfolioAsset_native* portfolio_asset_new(double portfolio_weight, byte* name, int name_len, double* values, nuint len);
|
||||||
|
|
||||||
|
[DllImport(__DllName, EntryPoint = "portfolio_asset_destroy", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||||
|
internal static extern void portfolio_asset_destroy(PortfolioAsset_native* asset);
|
||||||
|
|
||||||
|
[DllImport(__DllName, EntryPoint = "portfolio_asset_apply_rates_of_change", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||||
|
internal static extern void portfolio_asset_apply_rates_of_change(PortfolioAsset_native* asset);
|
||||||
|
|
||||||
|
[DllImport(__DllName, EntryPoint = "portfolio_asset_get_mean_and_std", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||||
|
internal static extern Tuple portfolio_asset_get_mean_and_std(PortfolioAsset_native* asset);
|
||||||
|
|
||||||
|
[DllImport(__DllName, EntryPoint = "portfolio_new", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||||
|
internal static extern Portfolio_native* portfolio_new();
|
||||||
|
|
||||||
|
[DllImport(__DllName, EntryPoint = "portfolio_destroy", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||||
|
internal static extern void portfolio_destroy(Portfolio_native* portfolio);
|
||||||
|
|
||||||
|
[DllImport(__DllName, EntryPoint = "portfolio_add_asset", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||||
|
internal static extern void portfolio_add_asset(Portfolio_native* portfolio, PortfolioAsset_native* asset);
|
||||||
|
|
||||||
|
[DllImport(__DllName, EntryPoint = "portfolio_apply_rates_of_change", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||||
|
internal static extern void portfolio_apply_rates_of_change(Portfolio_native* portfolio);
|
||||||
|
|
||||||
|
[DllImport(__DllName, EntryPoint = "portfolio_valid_sizes", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||||
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
|
internal static extern bool portfolio_valid_sizes(Portfolio_native* portfolio);
|
||||||
|
|
||||||
|
[DllImport(__DllName, EntryPoint = "portfolio_valid_weights", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||||
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
|
internal static extern bool portfolio_valid_weights(Portfolio_native* portfolio);
|
||||||
|
|
||||||
|
[DllImport(__DllName, EntryPoint = "portfolio_is_valid", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||||
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
|
internal static extern bool portfolio_is_valid(Portfolio_native* portfolio);
|
||||||
|
|
||||||
|
[DllImport(__DllName, EntryPoint = "portfolio_get_mean_and_std", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||||
|
internal static extern Tuple portfolio_get_mean_and_std(Portfolio_native* portfolio);
|
||||||
|
|
||||||
|
[DllImport(__DllName, EntryPoint = "portfolio_value_at_risk", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||||
|
internal static extern NullableFloat portfolio_value_at_risk(Portfolio_native* portfolio, double confidence, double initial_investment);
|
||||||
|
|
||||||
|
[DllImport(__DllName, EntryPoint = "portfolio_value_at_risk_percent", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)]
|
||||||
|
internal static extern NullableFloat portfolio_value_at_risk_percent(Portfolio_native* portfolio, double confidence);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
internal unsafe partial struct Portfolio
|
internal unsafe partial struct Tuple
|
||||||
|
{
|
||||||
|
public double one;
|
||||||
|
public double two;
|
||||||
|
[MarshalAs(UnmanagedType.U1)] public bool is_valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal unsafe partial struct NullableFloat
|
||||||
|
{
|
||||||
|
public double val;
|
||||||
|
[MarshalAs(UnmanagedType.U1)] public bool is_valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal unsafe partial struct Portfolio_native
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
internal unsafe partial struct PortfolioAsset
|
internal unsafe partial struct PortfolioAsset_native
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
internal unsafe partial struct OptionVariables
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
internal unsafe partial struct CallOption
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
internal unsafe partial struct PutOption
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
internal unsafe partial struct OptionGreeks
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
internal enum ValueType : byte
|
|
||||||
{
|
|
||||||
Absolute,
|
|
||||||
RateOfChange,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
126
FinLib.NET/FinLib/Portfolio.cs
Normal file
126
FinLib.NET/FinLib/Portfolio.cs
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FinLib;
|
||||||
|
|
||||||
|
public class Portfolio: IDisposable
|
||||||
|
{
|
||||||
|
private readonly unsafe Portfolio_native* _portfolio;
|
||||||
|
internal unsafe Portfolio_native* GetPtr() => _portfolio;
|
||||||
|
|
||||||
|
public Portfolio()
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
_portfolio = NativeMethods.portfolio_new();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddAsset(double portfolioWeight, string assetName, IEnumerable<double> values)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
var n = Encoding.UTF8.GetBytes(assetName);
|
||||||
|
var v = values.ToArray();
|
||||||
|
fixed (byte* namePtr = n)
|
||||||
|
fixed (double* valuesPtr = v){
|
||||||
|
NativeMethods.portfolio_add_asset(_portfolio, NativeMethods.portfolio_asset_new(portfolioWeight, namePtr, assetName.Length, valuesPtr, (UIntPtr)v.Length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ValidSize()
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
return NativeMethods.portfolio_valid_sizes(_portfolio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ValidWeights()
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
return NativeMethods.portfolio_valid_weights(_portfolio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsValid()
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
return NativeMethods.portfolio_is_valid(_portfolio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyRatesOfChange()
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
NativeMethods.portfolio_apply_rates_of_change(_portfolio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public (double, double)? GetMeanAndStdDev()
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
var ret = NativeMethods.portfolio_get_mean_and_std(_portfolio);
|
||||||
|
if (ret.is_valid)
|
||||||
|
{
|
||||||
|
return (ret.one, ret.two);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double? ValueAtRisk(double confidence, double initialInvestment)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
var ret = NativeMethods.portfolio_value_at_risk(_portfolio, confidence, initialInvestment);
|
||||||
|
if (ret.is_valid)
|
||||||
|
{
|
||||||
|
return ret.val;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double? ValueAtRiskPercent(double confidence)
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
var ret = NativeMethods.portfolio_value_at_risk_percent(_portfolio, confidence);
|
||||||
|
if (ret.is_valid)
|
||||||
|
{
|
||||||
|
return ret.val;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReleaseUnmanagedResources()
|
||||||
|
{
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
NativeMethods.portfolio_destroy(_portfolio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
ReleaseUnmanagedResources();
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Portfolio()
|
||||||
|
{
|
||||||
|
ReleaseUnmanagedResources();
|
||||||
|
}
|
||||||
|
}
|
26
finlib-cpp/CMakeLists.txt
Normal file
26
finlib-cpp/CMakeLists.txt
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.19)
|
||||||
|
|
||||||
|
|
||||||
|
if(${CMAKE_VERSION} VERSION_LESS 3.19)
|
||||||
|
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
project(finlib-cpp)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
|
|
||||||
|
set(CMAKE_INSTALL_PREFIX ${PROJECT_SOURCE_DIR})
|
||||||
|
|
||||||
|
set(FINLIB_INSTALL_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include)
|
||||||
|
set(FINLIB_INSTALL_BIN_DIR ${PROJECT_SOURCE_DIR}/bin)
|
||||||
|
set(FINLIB_INSTALL_LIB_DIR ${PROJECT_SOURCE_DIR}/lib)
|
||||||
|
|
||||||
|
set(FINLIB_HEADERS_DIR ${PROJECT_SOURCE_DIR}/src/finlib)
|
||||||
|
|
||||||
|
include_directories(${FINLIB_INSTALL_INCLUDE_DIR})
|
||||||
|
include_directories(${FINLIB_HEADERS_DIR})
|
||||||
|
|
||||||
|
add_subdirectory(src)
|
||||||
|
add_subdirectory(test)
|
3
finlib-cpp/README.md
Normal file
3
finlib-cpp/README.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# finlib-cpp
|
||||||
|
|
||||||
|
[StackOverflow - How can I build Rust code with a C++/Qt/CMake project?](https://stackoverflow.com/questions/31162438/how-can-i-build-rust-code-with-a-c-qt-cmake-project)
|
@ -1,32 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
/* Generated with cbindgen:0.28.0 */
|
|
||||||
|
|
||||||
/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */
|
|
||||||
|
|
||||||
#include <cstdarg>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <ostream>
|
|
||||||
#include <new>
|
|
||||||
|
|
||||||
|
|
||||||
namespace finlib {
|
|
||||||
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
const double *covariance(const double *arr, size_t len, const double *arr_two, size_t len_two);
|
|
||||||
|
|
||||||
const double *historical_value_at_risk(const double *arr, size_t len, double confidence);
|
|
||||||
|
|
||||||
double interest_compound(double principal, double rate, double time, double n);
|
|
||||||
|
|
||||||
double scale_value_at_risk(double initial_value, ptrdiff_t time_cycles);
|
|
||||||
|
|
||||||
const double *varcovar_value_at_risk(const double *arr, size_t len, double confidence);
|
|
||||||
|
|
||||||
} // extern "C"
|
|
||||||
|
|
||||||
} // namespace finlib
|
|
85
finlib-cpp/include/finlib/finlib-native.h
Normal file
85
finlib-cpp/include/finlib/finlib-native.h
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/* Generated with cbindgen:0.28.0 */
|
||||||
|
|
||||||
|
/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */
|
||||||
|
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <ostream>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
|
||||||
|
namespace finlib {
|
||||||
|
|
||||||
|
/// Describes a Portfolio as a collection of [`PortfolioAsset`]s
|
||||||
|
struct Portfolio;
|
||||||
|
|
||||||
|
/// Describes a single instrument as a list of previous values with an associated portfolio proportion
|
||||||
|
struct PortfolioAsset;
|
||||||
|
|
||||||
|
struct NullableFloat
|
||||||
|
{
|
||||||
|
double Val;
|
||||||
|
bool IsValid;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Tuple
|
||||||
|
{
|
||||||
|
double One;
|
||||||
|
double Two;
|
||||||
|
bool IsValid;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
NullableFloat covariance(const double *arr, size_t len, const double *arr_two, size_t len_two);
|
||||||
|
|
||||||
|
NullableFloat historical_value_at_risk(const double *arr, size_t len, double confidence);
|
||||||
|
|
||||||
|
double interest_compound(double principal, double rate, double time, double n);
|
||||||
|
|
||||||
|
void portfolio_add_asset(Portfolio *portfolio, PortfolioAsset *asset);
|
||||||
|
|
||||||
|
void portfolio_apply_rates_of_change(Portfolio *portfolio);
|
||||||
|
|
||||||
|
void portfolio_asset_apply_rates_of_change(PortfolioAsset *asset);
|
||||||
|
|
||||||
|
void portfolio_asset_destroy(PortfolioAsset *asset);
|
||||||
|
|
||||||
|
Tuple portfolio_asset_get_mean_and_std(PortfolioAsset *asset);
|
||||||
|
|
||||||
|
PortfolioAsset *portfolio_asset_new(double portfolio_weight,
|
||||||
|
const uint8_t *name,
|
||||||
|
int32_t name_len,
|
||||||
|
const double *values,
|
||||||
|
size_t len);
|
||||||
|
|
||||||
|
void portfolio_destroy(Portfolio *portfolio);
|
||||||
|
|
||||||
|
Tuple portfolio_get_mean_and_std(Portfolio *portfolio);
|
||||||
|
|
||||||
|
bool portfolio_is_valid(Portfolio *portfolio);
|
||||||
|
|
||||||
|
Portfolio *portfolio_new();
|
||||||
|
|
||||||
|
bool portfolio_valid_sizes(Portfolio *portfolio);
|
||||||
|
|
||||||
|
bool portfolio_valid_weights(Portfolio *portfolio);
|
||||||
|
|
||||||
|
NullableFloat portfolio_value_at_risk(Portfolio *portfolio,
|
||||||
|
double confidence,
|
||||||
|
double initial_investment);
|
||||||
|
|
||||||
|
NullableFloat portfolio_value_at_risk_percent(Portfolio *portfolio, double confidence);
|
||||||
|
|
||||||
|
double scale_value_at_risk(double initial_value, ptrdiff_t time_cycles);
|
||||||
|
|
||||||
|
NullableFloat varcovar_value_at_risk(const double *arr, size_t len, double confidence);
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
|
||||||
|
} // namespace finlib
|
10
finlib-cpp/src/CMakeLists.txt
Normal file
10
finlib-cpp/src/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.19)
|
||||||
|
project(finexe)
|
||||||
|
|
||||||
|
add_subdirectory(finlib)
|
||||||
|
set(SOURCE_FILES main.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(finexe ${SOURCE_FILES})
|
||||||
|
target_link_libraries(finexe finlib)
|
||||||
|
install(TARGETS finexe DESTINATION ${FINLIB_INSTALL_BIN_DIR})
|
28
finlib-cpp/src/finlib/CMakeLists.txt
Normal file
28
finlib-cpp/src/finlib/CMakeLists.txt
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
include(ExternalProject)
|
||||||
|
|
||||||
|
project(finlib C CXX)
|
||||||
|
|
||||||
|
set(SOURCE_FILES
|
||||||
|
finlib.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(finlib SHARED STATIC ${SOURCE_FILES})
|
||||||
|
|
||||||
|
ExternalProject_Add(
|
||||||
|
finlibrs
|
||||||
|
DOWNLOAD_COMMAND ""
|
||||||
|
CONFIGURE_COMMAND ""
|
||||||
|
BUILD_COMMAND cargo build
|
||||||
|
COMMAND cargo build --release
|
||||||
|
BINARY_DIR "${CMAKE_SOURCE_DIR}/../"
|
||||||
|
INSTALL_COMMAND ""
|
||||||
|
LOG_BUILD ON)
|
||||||
|
|
||||||
|
add_dependencies(finlib finlibrs)
|
||||||
|
target_link_libraries(finlib
|
||||||
|
debug "${CMAKE_SOURCE_DIR}/../target/debug/libfinlib_ffi.a"
|
||||||
|
optimized "${CMAKE_SOURCE_DIR}/../target/release/libfinlib_ffi.a"
|
||||||
|
)
|
||||||
|
|
||||||
|
install(TARGETS finlib DESTINATION ${FINLIB_INSTALL_LIB_DIR})
|
||||||
|
install(FILES finlib.h DESTINATION ${FINLIB_INSTALL_INCLUDE_DIR})
|
17
finlib-cpp/src/finlib/finlib.cpp
Normal file
17
finlib-cpp/src/finlib/finlib.cpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
//
|
||||||
|
// Created by Andy Pack on 21/02/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "finlib.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace finlib {
|
||||||
|
void init() {
|
||||||
|
std::cout << "Initializing..." << std::endl;
|
||||||
|
|
||||||
|
auto ret = interest_compound(100, .05, 1, 1.0);
|
||||||
|
|
||||||
|
std::cout << "Answer: " << ret << std::endl;
|
||||||
|
}
|
||||||
|
}
|
7
finlib-cpp/src/finlib/finlib.hpp
Normal file
7
finlib-cpp/src/finlib/finlib.hpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <finlib/finlib-native.h>
|
||||||
|
|
||||||
|
namespace finlib {
|
||||||
|
void init();
|
||||||
|
}
|
11
finlib-cpp/src/main.cpp
Normal file
11
finlib-cpp/src/main.cpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <finlib.hpp>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
int main(int argc, const char *argv[]) {
|
||||||
|
|
||||||
|
finlib::init();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
28
finlib-cpp/test/CMakeLists.txt
Normal file
28
finlib-cpp/test/CMakeLists.txt
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.19)
|
||||||
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
project(finlib_tests)
|
||||||
|
|
||||||
|
include_directories(${FINLIB_HEADERS_DIR})
|
||||||
|
|
||||||
|
set(SOURCE_FILES
|
||||||
|
src/basic_test.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(
|
||||||
|
googletest
|
||||||
|
GIT_REPOSITORY https://github.com/google/googletest
|
||||||
|
GIT_TAG v1.16.0
|
||||||
|
)
|
||||||
|
# For Windows: Prevent overriding the parent project's compiler/linker settings
|
||||||
|
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||||
|
FetchContent_MakeAvailable(googletest)
|
||||||
|
|
||||||
|
add_executable(finlib_tests ${SOURCE_FILES})
|
||||||
|
target_link_libraries(finlib_tests finlib GTest::gtest_main)
|
||||||
|
install(TARGETS finlib_tests DESTINATION bin)
|
||||||
|
|
||||||
|
include(GoogleTest)
|
||||||
|
gtest_discover_tests(finlib_tests)
|
28
finlib-cpp/test/src/basic_test.cpp
Normal file
28
finlib-cpp/test/src/basic_test.cpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
|
// Demonstrate some basic assertions.
|
||||||
|
TEST(HelloTest, BasicAssertions) {
|
||||||
|
// Expect two strings not to be equal.
|
||||||
|
EXPECT_STRNE("hello", "world");
|
||||||
|
// Expect equality.
|
||||||
|
EXPECT_EQ(7 * 6, 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Demonstrate some basic assertions.
|
||||||
|
TEST(HelloTest, BasicAssertions2) {
|
||||||
|
// Expect two strings not to be equal.
|
||||||
|
EXPECT_STRNE("hello", "world");
|
||||||
|
// Expect equality.
|
||||||
|
EXPECT_EQ(7 * 6, 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Demonstrate some basic assertions.
|
||||||
|
TEST(HelloTest, BasicAssertions3) {
|
||||||
|
// Expect two strings not to be equal.
|
||||||
|
EXPECT_STRNE("hello", "world");
|
||||||
|
// Expect equality.
|
||||||
|
EXPECT_EQ(7 * 6, 42);
|
||||||
|
}
|
@ -11,7 +11,7 @@ readme.workspace = true
|
|||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib", "staticlib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
finlib = { path = "../finlib", features = ["ffi"] }
|
finlib = { path = "../finlib", features = ["ffi"] }
|
||||||
|
@ -14,24 +14,19 @@ fn main() {
|
|||||||
.with_config(config)
|
.with_config(config)
|
||||||
.generate()
|
.generate()
|
||||||
.expect("Unable to generate bindings")
|
.expect("Unable to generate bindings")
|
||||||
.write_to_file("../finlib-cpp/include/finlib-native.h");
|
.write_to_file("../finlib-cpp/include/finlib/finlib-native.h");
|
||||||
|
|
||||||
csbindgen::Builder::default()
|
csbindgen::Builder::default()
|
||||||
.input_extern_file("src/lib.rs")
|
.input_extern_file("src/lib.rs")
|
||||||
.input_extern_file("../finlib/src/lib.rs")
|
.input_extern_file("src/portfolio.rs")
|
||||||
.input_extern_file("../finlib/src/risk/portfolio.rs")
|
.input_extern_file("../finlib/src/risk/portfolio.rs")
|
||||||
.input_extern_file("../finlib/src/options/blackscholes/mod.rs")
|
|
||||||
.csharp_dll_name("libfinlib_ffi")
|
.csharp_dll_name("libfinlib_ffi")
|
||||||
.always_included_types([
|
|
||||||
"Portfolio",
|
|
||||||
"ValueType",
|
|
||||||
"PortfolioAsset",
|
|
||||||
"OptionVariables",
|
|
||||||
"CallOption",
|
|
||||||
"PutOption",
|
|
||||||
"OptionGreeks",
|
|
||||||
])
|
|
||||||
.csharp_namespace("FinLib")
|
.csharp_namespace("FinLib")
|
||||||
|
.csharp_type_rename(|rust_type_name| match rust_type_name.as_str() { // optional, default: `|x| x`
|
||||||
|
"Portfolio" => "Portfolio_native".into(),
|
||||||
|
"PortfolioAsset" => "PortfolioAsset_native".into(),
|
||||||
|
_ => rust_type_name,
|
||||||
|
})
|
||||||
.generate_csharp_file("../FinLib.NET/FinLib/NativeMethods.g.cs")
|
.generate_csharp_file("../FinLib.NET/FinLib/NativeMethods.g.cs")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
@ -1,13 +1,29 @@
|
|||||||
use std::ptr::null;
|
mod portfolio;
|
||||||
|
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct Tuple {
|
||||||
|
one: f64,
|
||||||
|
two: f64,
|
||||||
|
is_valid: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct NullableFloat {
|
||||||
|
val: f64,
|
||||||
|
is_valid: bool
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn interest_compound(principal: f64, rate: f64, time: f64, n: f64) -> f64 {
|
pub extern "C" fn interest_compound(principal: f64, rate: f64, time: f64, n: f64) -> f64 {
|
||||||
finlib::interest::compound(principal, rate, time, n)
|
finlib::interest::compound(principal, rate, time, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn covariance(arr: *const f64, len: usize, arr_two: *const f64, len_two: usize) -> *const f64 {
|
pub unsafe extern "C" fn covariance(arr: *const f64, len: usize, arr_two: *const f64, len_two: usize) -> NullableFloat {
|
||||||
let input_array = unsafe {
|
let input_array = unsafe {
|
||||||
assert!(!arr.is_null());
|
assert!(!arr.is_null());
|
||||||
slice::from_raw_parts(arr, len)
|
slice::from_raw_parts(arr, len)
|
||||||
@ -19,30 +35,36 @@ pub unsafe extern "C" fn covariance(arr: *const f64, len: usize, arr_two: *const
|
|||||||
};
|
};
|
||||||
|
|
||||||
match finlib::stats::covariance(input_array, input_array_two) {
|
match finlib::stats::covariance(input_array, input_array_two) {
|
||||||
None => null(),
|
None => NullableFloat { val: 0.0, is_valid: false },
|
||||||
Some(v) => Box::into_raw(Box::new(v))
|
Some(v) => NullableFloat { val: v, is_valid: true }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn historical_value_at_risk(arr: *const f64, len: usize, confidence: f64) -> *const f64 {
|
pub unsafe extern "C" fn historical_value_at_risk(arr: *const f64, len: usize, confidence: f64) -> NullableFloat {
|
||||||
let input_array = unsafe {
|
let input_array = unsafe {
|
||||||
assert!(!arr.is_null());
|
assert!(!arr.is_null());
|
||||||
slice::from_raw_parts(arr, len)
|
slice::from_raw_parts(arr, len)
|
||||||
};
|
};
|
||||||
|
|
||||||
Box::into_raw(Box::new(finlib::risk::var::historical::value_at_risk(input_array, confidence)))
|
NullableFloat {
|
||||||
|
val: finlib::risk::var::historical::value_at_risk(input_array, confidence),
|
||||||
|
is_valid: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn varcovar_value_at_risk(arr: *const f64, len: usize, confidence: f64) -> *const f64 {
|
pub unsafe extern "C" fn varcovar_value_at_risk(arr: *const f64, len: usize, confidence: f64) -> NullableFloat {
|
||||||
let input_array = unsafe {
|
let input_array = unsafe {
|
||||||
assert!(!arr.is_null());
|
assert!(!arr.is_null());
|
||||||
slice::from_raw_parts(arr, len)
|
slice::from_raw_parts(arr, len)
|
||||||
};
|
};
|
||||||
|
|
||||||
Box::into_raw(Box::new(finlib::risk::var::varcovar::value_at_risk_percent(input_array, confidence)))
|
NullableFloat {
|
||||||
|
val: finlib::risk::var::varcovar::value_at_risk_percent(input_array, confidence),
|
||||||
|
is_valid: true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
112
finlib-ffi/src/portfolio.rs
Normal file
112
finlib-ffi/src/portfolio.rs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
use std::{ptr, slice};
|
||||||
|
use finlib::risk::portfolio::{Portfolio, PortfolioAsset};
|
||||||
|
use crate::{NullableFloat, Tuple};
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn portfolio_asset_new(portfolio_weight: f64, name: *const u8, name_len: i32, values: *const f64, len: usize) -> *mut PortfolioAsset {
|
||||||
|
|
||||||
|
if name.is_null() {
|
||||||
|
return ptr::null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
let slice = slice::from_raw_parts(name, name_len as usize);
|
||||||
|
let name = String::from_utf8_unchecked(slice.to_vec());
|
||||||
|
|
||||||
|
let input_array = unsafe {
|
||||||
|
assert!(!values.is_null());
|
||||||
|
slice::from_raw_parts(values, len)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Box::into_raw(Box::new(PortfolioAsset::new(portfolio_weight, name, input_array.to_vec())))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn portfolio_asset_destroy(asset: *mut PortfolioAsset) {
|
||||||
|
if !asset.is_null() {
|
||||||
|
drop(Box::from_raw(asset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn portfolio_asset_apply_rates_of_change(asset: *mut PortfolioAsset) {
|
||||||
|
(&mut *asset).apply_rates_of_change();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn portfolio_asset_get_mean_and_std(asset: *mut PortfolioAsset) -> Tuple {
|
||||||
|
match (&mut *asset).get_mean_and_std() {
|
||||||
|
None => Tuple { one: 0.0, two: 0.0, is_valid: false },
|
||||||
|
Some((one, two)) => {
|
||||||
|
Tuple {
|
||||||
|
one, two, is_valid: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn portfolio_new() -> *mut Portfolio {
|
||||||
|
Box::into_raw(Box::new(Portfolio::from(vec![])))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn portfolio_destroy(portfolio: *mut Portfolio) {
|
||||||
|
if !portfolio.is_null() {
|
||||||
|
drop(Box::from_raw(portfolio));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn portfolio_add_asset(portfolio: *mut Portfolio, asset: *mut PortfolioAsset) {
|
||||||
|
(&mut *portfolio).add_asset((*asset).clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn portfolio_apply_rates_of_change(portfolio: *mut Portfolio) {
|
||||||
|
(&mut *portfolio).apply_rates_of_change()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn portfolio_valid_sizes(portfolio: *mut Portfolio) -> bool {
|
||||||
|
(&mut *portfolio).valid_sizes()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn portfolio_valid_weights(portfolio: *mut Portfolio) -> bool {
|
||||||
|
(&mut *portfolio).valid_weights()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn portfolio_is_valid(portfolio: *mut Portfolio) -> bool {
|
||||||
|
(&mut *portfolio).is_valid()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn portfolio_get_mean_and_std(portfolio: *mut Portfolio) -> Tuple {
|
||||||
|
match (&mut *portfolio).get_mean_and_std() {
|
||||||
|
None => Tuple { one: 0.0, two: 0.0, is_valid: false },
|
||||||
|
Some((one, two)) => {
|
||||||
|
Tuple {
|
||||||
|
one, two, is_valid: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn portfolio_value_at_risk(portfolio: *mut Portfolio, confidence: f64, initial_investment: f64) -> NullableFloat {
|
||||||
|
match (&mut *portfolio).value_at_risk(confidence, initial_investment) {
|
||||||
|
None => NullableFloat { val: 0.0, is_valid: false },
|
||||||
|
Some(v) => NullableFloat { val: v, is_valid: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn portfolio_value_at_risk_percent(portfolio: *mut Portfolio, confidence: f64) -> NullableFloat {
|
||||||
|
match (&mut *portfolio).value_at_risk_percent(confidence) {
|
||||||
|
None => NullableFloat { val: 0.0, is_valid: false },
|
||||||
|
Some(v) => NullableFloat { val: v, is_valid: true }
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
|
use crate::options::blackscholes::{OptionVariables};
|
||||||
use core::ops::Range;
|
use core::ops::Range;
|
||||||
use std::sync::{Arc, Mutex};
|
|
||||||
use crate::options::blackscholes::{CallOption, Option, OptionVariables, PutOption};
|
|
||||||
|
|
||||||
pub struct OptionSurface {
|
pub struct OptionSurface {
|
||||||
underlying_price: Range<isize>,
|
underlying_price: Range<isize>,
|
||||||
@ -84,30 +83,30 @@ impl OptionSurface {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::options::blackscholes::{generate_options, CallOption, Option, PutOption};
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::options::blackscholes::generate_options;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn walk_test() {
|
fn walk_test() {
|
||||||
let w = OptionSurface::from(
|
let w = OptionSurface::from(
|
||||||
(0 .. 50),
|
0 .. 50,
|
||||||
(100., 200.),
|
(100., 200.),
|
||||||
(0 .. 50),
|
0 .. 50,
|
||||||
(100., 200.),
|
(100., 200.),
|
||||||
(0 .. 5),
|
0 .. 5,
|
||||||
(0.25, 0.50),
|
(0.25, 0.50),
|
||||||
(0 .. 10),
|
0 .. 10,
|
||||||
(0.05, 0.08),
|
(0.05, 0.08),
|
||||||
(0 .. 1),
|
0 .. 1,
|
||||||
(0.01, 0.02),
|
(0.01, 0.02),
|
||||||
(0 .. 10),
|
0 .. 10,
|
||||||
(30./365.25, 30./365.25),
|
(30./365.25, 30./365.25),
|
||||||
);
|
);
|
||||||
|
|
||||||
let a = w.walk();
|
let a = w.walk();
|
||||||
|
|
||||||
let options = generate_options(&a);
|
let _ = generate_options(&a);
|
||||||
|
|
||||||
let a1 = a.first();
|
let _ = a.first();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -36,10 +36,10 @@ pub enum ValueType {
|
|||||||
#[cfg_attr(feature = "ffi", repr(C))]
|
#[cfg_attr(feature = "ffi", repr(C))]
|
||||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||||
pub struct PortfolioAsset {
|
pub struct PortfolioAsset {
|
||||||
portfolio_weight: f64,
|
pub portfolio_weight: f64,
|
||||||
name: String,
|
name: String,
|
||||||
values: Vec<f64>,
|
values: Vec<f64>,
|
||||||
value_type: ValueType
|
pub value_type: ValueType
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PortfolioAsset {
|
impl PortfolioAsset {
|
||||||
@ -84,6 +84,10 @@ impl Portfolio {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_asset(&mut self, asset: PortfolioAsset) {
|
||||||
|
self.assets.push(asset);
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the proportions of a portfolio's assets
|
/// Return the proportions of a portfolio's assets
|
||||||
///
|
///
|
||||||
/// In a properly formed Portfolio these will add up to 1.0
|
/// In a properly formed Portfolio these will add up to 1.0
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
use crate::stats;
|
use crate::stats;
|
||||||
use crate::util::roc::rates_of_change;
|
use crate::util::roc::rates_of_change;
|
||||||
|
|
||||||
use rayon::prelude::*;
|
|
||||||
use statrs::distribution::{ContinuousCDF, Normal};
|
use statrs::distribution::{ContinuousCDF, Normal};
|
||||||
// https://medium.com/@serdarilarslan/value-at-risk-var-and-its-implementation-in-python-5c9150f73b0e
|
// https://medium.com/@serdarilarslan/value-at-risk-var-and-its-implementation-in-python-5c9150f73b0e
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user