diff --git a/.gitignore b/.gitignore
index a592abc..002cfdd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
 /target
 bin
 obj
+cmake-build-debug
 .venv
 .idea
 /finlib-wasm/pkg
diff --git a/Cargo.lock b/Cargo.lock
index bb049d9..9916d20 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -340,7 +340,7 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
 
 [[package]]
 name = "finlib"
-version = "0.0.6"
+version = "0.0.7"
 dependencies = [
  "criterion",
  "getrandom 0.2.15",
@@ -357,7 +357,7 @@ dependencies = [
 
 [[package]]
 name = "finlib-ffi"
-version = "0.0.6"
+version = "0.0.7"
 dependencies = [
  "cbindgen",
  "csbindgen",
@@ -366,7 +366,7 @@ dependencies = [
 
 [[package]]
 name = "finlib-wasm"
-version = "0.0.6"
+version = "0.0.7"
 dependencies = [
  "console_error_panic_hook",
  "console_log",
@@ -759,7 +759,7 @@ dependencies = [
 
 [[package]]
 name = "pyfinlib"
-version = "0.0.6"
+version = "0.0.7"
 dependencies = [
  "finlib",
  "log",
diff --git a/Cargo.toml b/Cargo.toml
index 80c86e4..7c66c5c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,7 +14,7 @@ default-members = [
 ]
 
 [workspace.package]
-version = "0.0.6"
+version = "0.0.7"
 authors = ["sarsoo <andy@sarsoo.xyz>"]
 description = "Quant finance functions implemented in Rust"
 edition = "2021"
diff --git a/FinLib.NET/FinLib.Bench/Benchmarks/HistoricalVAR.cs b/FinLib.NET/FinLib.Bench/Benchmarks/HistoricalVAR.cs
index 186943f..0fe1ac2 100644
--- a/FinLib.NET/FinLib.Bench/Benchmarks/HistoricalVAR.cs
+++ b/FinLib.NET/FinLib.Bench/Benchmarks/HistoricalVAR.cs
@@ -30,5 +30,5 @@ public class HistoricalVar
     public double FinLibDotnet() => HistoricalVARDotnet.ValueAtRisk(data.ToList(), confidence);
 
     [Benchmark]
-    public double FinLibRust() => FinLib.Risk.ValueAtRisk.Historical(data, confidence);
+    public double FinLibRust() => FinLib.Risk.ValueAtRisk.Historical(data, confidence)!.Value;
 }
\ No newline at end of file
diff --git a/FinLib.NET/FinLib.Test/Portfolio.cs b/FinLib.NET/FinLib.Test/Portfolio.cs
new file mode 100644
index 0000000..a2183da
--- /dev/null
+++ b/FinLib.NET/FinLib.Test/Portfolio.cs
@@ -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();
+    }
+}
\ No newline at end of file
diff --git a/FinLib.NET/FinLib/FinLib.Risk.cs b/FinLib.NET/FinLib/FinLib.Risk.cs
index bba9bee..41b2c1a 100644
--- a/FinLib.NET/FinLib/FinLib.Risk.cs
+++ b/FinLib.NET/FinLib/FinLib.Risk.cs
@@ -7,26 +7,36 @@ namespace FinLib.Risk;
 
 public static class ValueAtRisk
 {
-    public static double Historical(IEnumerable<double> values, double confidence)
+    public static double? Historical(IEnumerable<double> values, double confidence)
     {
         unsafe {
             var valueArr = values.ToArray();
             fixed (double* ptrOne = valueArr) {
                 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 {
             var valueArr = values.ToArray();
             fixed (double* ptrOne = valueArr) {
                 var ret = NativeMethods.varcovar_value_at_risk(ptrOne, (UIntPtr)valueArr.Length, confidence);
 
-                return *ret;
+                if (ret.is_valid)
+                {
+                    return ret.val;
+                }
+
+                return null;
             }
         }
     }
diff --git a/FinLib.NET/FinLib/FinLib.Stats.cs b/FinLib.NET/FinLib/FinLib.Stats.cs
index 1483ee4..b9bd2ce 100644
--- a/FinLib.NET/FinLib/FinLib.Stats.cs
+++ b/FinLib.NET/FinLib/FinLib.Stats.cs
@@ -16,14 +16,12 @@ public static class Stats
             fixed (double* ptrTwo = valuesTwoArr) {
                 var ret = NativeMethods.covariance(ptrOne, (UIntPtr)valuesOneArr.Length, ptrTwo, (UIntPtr) valuesTwoArr.Length);
 
-                if (ret == null)
+                if (ret.is_valid)
                 {
-                    return null;
-                }
-                else
-                {
-                    return *ret;
+                    return ret.val;
                 }
+
+                return null;
             }
         }
     }
diff --git a/FinLib.NET/FinLib/NativeMethods.cs b/FinLib.NET/FinLib/NativeMethods.cs
index 038515a..a0feb89 100644
--- a/FinLib.NET/FinLib/NativeMethods.cs
+++ b/FinLib.NET/FinLib/NativeMethods.cs
@@ -1,9 +1,7 @@
-using GroupedNativeMethodsGenerator;
 
 namespace FinLib;
 
-[GroupedNativeMethods]
-internal static unsafe partial class NativeMethods
+internal static partial class NativeMethods
 {
 
 }
\ No newline at end of file
diff --git a/FinLib.NET/FinLib/NativeMethods.g.cs b/FinLib.NET/FinLib/NativeMethods.g.cs
index fcbb16b..07f8c5b 100644
--- a/FinLib.NET/FinLib/NativeMethods.g.cs
+++ b/FinLib.NET/FinLib/NativeMethods.g.cs
@@ -20,56 +20,90 @@ namespace FinLib
         internal static extern double interest_compound(double principal, double rate, double time, double n);
 
         [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)]
-        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)]
-        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)]
         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)]
-    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)]
-    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,
-    }
 
 
 }
diff --git a/FinLib.NET/FinLib/Portfolio.cs b/FinLib.NET/FinLib/Portfolio.cs
new file mode 100644
index 0000000..aa11210
--- /dev/null
+++ b/FinLib.NET/FinLib/Portfolio.cs
@@ -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();
+    }
+}
\ No newline at end of file
diff --git a/finlib-cpp/CMakeLists.txt b/finlib-cpp/CMakeLists.txt
new file mode 100644
index 0000000..e013ffc
--- /dev/null
+++ b/finlib-cpp/CMakeLists.txt
@@ -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)
diff --git a/finlib-cpp/README.md b/finlib-cpp/README.md
new file mode 100644
index 0000000..9191209
--- /dev/null
+++ b/finlib-cpp/README.md
@@ -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)
\ No newline at end of file
diff --git a/finlib-cpp/include/finlib-native.h b/finlib-cpp/include/finlib-native.h
deleted file mode 100644
index dea90d7..0000000
--- a/finlib-cpp/include/finlib-native.h
+++ /dev/null
@@ -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
diff --git a/finlib-cpp/include/finlib/finlib-native.h b/finlib-cpp/include/finlib/finlib-native.h
new file mode 100644
index 0000000..4358da3
--- /dev/null
+++ b/finlib-cpp/include/finlib/finlib-native.h
@@ -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
diff --git a/finlib-cpp/src/CMakeLists.txt b/finlib-cpp/src/CMakeLists.txt
new file mode 100644
index 0000000..cbfe99f
--- /dev/null
+++ b/finlib-cpp/src/CMakeLists.txt
@@ -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})
\ No newline at end of file
diff --git a/finlib-cpp/src/finlib/CMakeLists.txt b/finlib-cpp/src/finlib/CMakeLists.txt
new file mode 100644
index 0000000..cbf731b
--- /dev/null
+++ b/finlib-cpp/src/finlib/CMakeLists.txt
@@ -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})
\ No newline at end of file
diff --git a/finlib-cpp/src/finlib/finlib.cpp b/finlib-cpp/src/finlib/finlib.cpp
new file mode 100644
index 0000000..a92e363
--- /dev/null
+++ b/finlib-cpp/src/finlib/finlib.cpp
@@ -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;
+    }
+}
diff --git a/finlib-cpp/src/finlib/finlib.hpp b/finlib-cpp/src/finlib/finlib.hpp
new file mode 100644
index 0000000..71bd78b
--- /dev/null
+++ b/finlib-cpp/src/finlib/finlib.hpp
@@ -0,0 +1,7 @@
+#pragma once
+
+#include <finlib/finlib-native.h>
+
+namespace finlib {
+    void init();
+}
\ No newline at end of file
diff --git a/finlib-cpp/src/main.cpp b/finlib-cpp/src/main.cpp
new file mode 100644
index 0000000..b20cd1b
--- /dev/null
+++ b/finlib-cpp/src/main.cpp
@@ -0,0 +1,11 @@
+#include <iostream>
+#include <finlib.hpp>
+
+using namespace std;
+
+int main(int argc, const char *argv[]) {
+
+    finlib::init();
+
+    return 0;
+}
\ No newline at end of file
diff --git a/finlib-cpp/test/CMakeLists.txt b/finlib-cpp/test/CMakeLists.txt
new file mode 100644
index 0000000..f46d352
--- /dev/null
+++ b/finlib-cpp/test/CMakeLists.txt
@@ -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)
\ No newline at end of file
diff --git a/finlib-cpp/test/src/basic_test.cpp b/finlib-cpp/test/src/basic_test.cpp
new file mode 100644
index 0000000..5e50c4e
--- /dev/null
+++ b/finlib-cpp/test/src/basic_test.cpp
@@ -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);
+}
\ No newline at end of file
diff --git a/finlib-ffi/Cargo.toml b/finlib-ffi/Cargo.toml
index 4056b84..cac44b1 100644
--- a/finlib-ffi/Cargo.toml
+++ b/finlib-ffi/Cargo.toml
@@ -11,7 +11,7 @@ readme.workspace = true
 license.workspace = true
 
 [lib]
-crate-type = ["cdylib"]
+crate-type = ["cdylib", "staticlib"]
 
 [dependencies]
 finlib = { path = "../finlib", features = ["ffi"] }
diff --git a/finlib-ffi/build.rs b/finlib-ffi/build.rs
index 08e65f4..3eff927 100644
--- a/finlib-ffi/build.rs
+++ b/finlib-ffi/build.rs
@@ -14,24 +14,19 @@ fn main() {
         .with_config(config)
         .generate()
         .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()
         .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/options/blackscholes/mod.rs")
         .csharp_dll_name("libfinlib_ffi")
-        .always_included_types([
-            "Portfolio",
-            "ValueType",
-            "PortfolioAsset",
-            "OptionVariables",
-            "CallOption",
-            "PutOption",
-            "OptionGreeks",
-        ])
         .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")
         .unwrap();
 }
\ No newline at end of file
diff --git a/finlib-ffi/src/lib.rs b/finlib-ffi/src/lib.rs
index a52cbcf..fb4f934 100644
--- a/finlib-ffi/src/lib.rs
+++ b/finlib-ffi/src/lib.rs
@@ -1,13 +1,29 @@
-use std::ptr::null;
+mod portfolio;
+
 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]
 pub extern "C" fn interest_compound(principal: f64, rate: f64, time: f64, n: f64) -> f64 {
     finlib::interest::compound(principal, rate, time, n)
 }
 
 #[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 {
         assert!(!arr.is_null());
         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) {
-        None => null(),
-        Some(v) => Box::into_raw(Box::new(v))
+        None => NullableFloat { val: 0.0, is_valid: false },
+        Some(v) => NullableFloat { val: v, is_valid: true }
     }
 
 }
 
 #[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 {
         assert!(!arr.is_null());
         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]
-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 {
         assert!(!arr.is_null());
         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]
diff --git a/finlib-ffi/src/portfolio.rs b/finlib-ffi/src/portfolio.rs
new file mode 100644
index 0000000..9aee046
--- /dev/null
+++ b/finlib-ffi/src/portfolio.rs
@@ -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 }
+    }
+}
diff --git a/finlib/src/options/blackscholes/option_surface.rs b/finlib/src/options/blackscholes/option_surface.rs
index cca2100..a77b071 100644
--- a/finlib/src/options/blackscholes/option_surface.rs
+++ b/finlib/src/options/blackscholes/option_surface.rs
@@ -1,6 +1,5 @@
+use crate::options::blackscholes::{OptionVariables};
 use core::ops::Range;
-use std::sync::{Arc, Mutex};
-use crate::options::blackscholes::{CallOption, Option, OptionVariables, PutOption};
 
 pub struct OptionSurface {
     underlying_price: Range<isize>,
@@ -84,30 +83,30 @@ impl OptionSurface {
 
 #[cfg(test)]
 mod tests {
-    use crate::options::blackscholes::{generate_options, CallOption, Option, PutOption};
     use super::*;
+    use crate::options::blackscholes::generate_options;
 
     #[test]
     fn walk_test() {
         let w = OptionSurface::from(
-            (0 .. 50),
+            0 .. 50,
             (100., 200.),
-            (0 .. 50),
+            0 .. 50,
             (100., 200.),
-            (0 .. 5),
+            0 .. 5,
             (0.25, 0.50),
-            (0 .. 10),
+            0 .. 10,
             (0.05, 0.08),
-            (0 .. 1),
+            0 .. 1,
             (0.01, 0.02),
-            (0 .. 10),
+            0 .. 10,
             (30./365.25, 30./365.25),
         );
 
         let a = w.walk();
 
-        let options = generate_options(&a);
+        let _ = generate_options(&a);
 
-        let a1 = a.first();
+        let _ = a.first();
     }
 }
\ No newline at end of file
diff --git a/finlib/src/risk/portfolio.rs b/finlib/src/risk/portfolio.rs
index 64231ed..fa7e5d6 100644
--- a/finlib/src/risk/portfolio.rs
+++ b/finlib/src/risk/portfolio.rs
@@ -36,10 +36,10 @@ pub enum ValueType {
 #[cfg_attr(feature = "ffi", repr(C))]
 #[derive(Clone, Debug, PartialEq, PartialOrd)]
 pub struct PortfolioAsset {
-    portfolio_weight: f64,
+    pub portfolio_weight: f64,
     name: String,
     values: Vec<f64>,
-    value_type: ValueType
+    pub value_type: ValueType
 }
 
 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
     ///
     /// In a properly formed Portfolio these will add up to 1.0
diff --git a/finlib/src/risk/var/varcovar.rs b/finlib/src/risk/var/varcovar.rs
index 0be44ad..8b7c1c0 100644
--- a/finlib/src/risk/var/varcovar.rs
+++ b/finlib/src/risk/var/varcovar.rs
@@ -1,7 +1,6 @@
 use crate::stats;
 use crate::util::roc::rates_of_change;
 
-use rayon::prelude::*;
 use statrs::distribution::{ContinuousCDF, Normal};
 // https://medium.com/@serdarilarslan/value-at-risk-var-and-its-implementation-in-python-5c9150f73b0e