Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ version: 2
shared: &shared
working_directory: ~/finsim

resource_class: medium+
steps:
- checkout

Expand Down
9 changes: 5 additions & 4 deletions .github/workflow/tests.yaml → .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ name: Python package CI

on:
push:
branches: [ master ]
branches:
- '**'
pull_request:
branches: [ master ]
branches: [ master, develop ]

jobs:
build_and_test:
Expand All @@ -23,9 +24,9 @@ jobs:
- name: Install dependencies
run: |
pip install --user --upgrade pip
pip install --user --upgrade setuptools wheel Cython
pip install --user --upgrade setuptools wheel
pip cache purge
pip install --user .
pip install --user .[test]
- name: Run tests
run: pytest --doctest-cython
run: pytest
3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "finsim"
version = "1.2.0"
version = "1.2.1"
authors = [
{name = "Kwan Yuet Stephen Ho", email = "stephenhky@yahoo.com.hk"}
]
Expand Down Expand Up @@ -37,7 +37,6 @@ dependencies = [
"openpyxl>=3.1.0",
"numba",
"typing-extensions",
"nptyping",
"pydantic"
]

Expand Down
28 changes: 14 additions & 14 deletions src/finsim/estimate/fit.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@

from typing import Literal
from typing import Literal, Annotated
from itertools import product

import numpy as np
from nptyping import NDArray, Shape, Float, Datetime64
from numpy.typing import NDArray

from .constants import dividing_factors_dict
from .native.pyfit import python_fit_BlackScholesMerton_model, python_fit_multivariate_BlackScholesMerton_model
Expand All @@ -12,8 +12,8 @@
# Note: always round-off to seconds first, but flexible about the unit to be used.

def fit_BlackScholesMerton_model(
timestamps: NDArray[Shape["*"], Datetime64],
prices: NDArray[Shape["*"], Float],
timestamps: Annotated[NDArray[np.datetime64], Literal["1D array"]],
prices: Annotated[NDArray[np.float64], Literal["1D array"]],
unit: Literal['second', 'minute', 'hour', 'day', 'year']='year'
) -> tuple[float, float]:
"""Fit a Black-Scholes-Merton model to price data to estimate rate of return and volatility.
Expand Down Expand Up @@ -46,10 +46,10 @@ def fit_BlackScholesMerton_model(


def fit_multivariate_BlackScholesMerton_model(
timestamps: NDArray[Shape["*"], Datetime64],
multiprices: NDArray[Shape["*, *"], Float],
timestamps: Annotated[NDArray[np.datetime64], Literal["1D array"]],
multiprices: Annotated[NDArray[np.float64], Literal["1D array"]],
unit: Literal['second', 'minute', 'hour', 'day', 'year']='year',
) -> tuple[NDArray[Shape["*"], Float], NDArray[Shape["*, *"], Float]]:
) -> tuple[Annotated[NDArray[np.float64], Literal["1D array"]], Annotated[NDArray[np.float64], Literal["2D array"]]]:
"""Fit a multivariate Black-Scholes-Merton model to price data for multiple assets.

This function estimates the parameters of the multivariate Black-Scholes-Merton model,
Expand Down Expand Up @@ -82,9 +82,9 @@ def fit_multivariate_BlackScholesMerton_model(
######## routines below are for time-weighted portfolio building

def fit_timeweighted_BlackScholesMerton_model(
timestamps: NDArray[Shape["*"], Datetime64],
prices: NDArray[Shape["*"], Float],
weights: NDArray[Shape["*"], Float],
timestamps: Annotated[NDArray[np.datetime64], Literal["1D array"]],
prices: Annotated[NDArray[np.float64], Literal["1D array"]],
weights: Annotated[NDArray[np.float64], Literal["1D array"]],
unit: Literal['second', 'minute', 'hour', 'day', 'year']='year'
) -> tuple[float, float]:
"""Fit a time-weighted Black-Scholes-Merton model to price data.
Expand Down Expand Up @@ -120,11 +120,11 @@ def fit_timeweighted_BlackScholesMerton_model(


def fit_timeweighted_multivariate_BlackScholesMerton_model(
timestamps: NDArray[Shape["*"], Datetime64],
multiprices: NDArray[Shape["*, *"], Float],
weights: NDArray[Shape["*"], Float],
timestamps: Annotated[NDArray[np.datetime64], Literal["1D array"]],
multiprices: Annotated[NDArray[np.float64], Literal["2D array"]],
weights: Annotated[NDArray[np.float64], Literal["1D array"]],
unit: Literal['second', 'minute', 'hour', 'day', 'year']='year'
) -> tuple[NDArray[Shape["*"], Float], NDArray[Shape["*, *"], Float]]:
) -> tuple[Annotated[NDArray[np.float64], Literal["1D array"]], Annotated[NDArray[np.float64], Literal["2D array"]]]:
"""Fit a time-weighted multivariate Black-Scholes-Merton model to price data for multiple assets.

This function estimates the parameters of the multivariate Black-Scholes-Merton model
Expand Down
14 changes: 8 additions & 6 deletions src/finsim/estimate/native/pyfit.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@

from typing import Literal, Annotated

import numpy as np
from numpy.typing import NDArray
import numba as nb
from nptyping import NDArray, Shape, Float


@nb.njit
def python_fit_BlackScholesMerton_model(
ts: NDArray[Shape["*"], Float],
prices: NDArray[Shape["*"], Float]
ts: Annotated[NDArray[np.float64], Literal["1D array"]],
prices: Annotated[NDArray[np.float64], Literal["1D array"]]
) -> tuple[float, float]:
"""Fit a Black-Scholes-Merton model to price data using Python implementation.

Expand Down Expand Up @@ -35,9 +37,9 @@ def python_fit_BlackScholesMerton_model(

@nb.njit
def python_fit_multivariate_BlackScholesMerton_model(
ts: NDArray[Shape["*"], Float],
multiprices: NDArray[Shape["*, *"], Float]
) -> tuple[NDArray[Shape["*"], Float], NDArray[Shape["*, *"], Float]]:
ts: Annotated[NDArray[np.float64], Literal["1D array"]],
multiprices: Annotated[NDArray[np.float64], Literal["2D array"]]
) -> tuple[Annotated[NDArray[np.float64], Literal["1D array"]], Annotated[NDArray[np.float64], Literal["2D array"]]]:
"""Fit a multivariate Black-Scholes-Merton model to price data for multiple assets.

This function estimates the parameters of the multivariate Black-Scholes-Merton model,
Expand Down
12 changes: 7 additions & 5 deletions src/finsim/estimate/native/pyrisk.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@

from typing import Literal, Annotated

import numpy as np
from numpy.typing import NDArray
import numba as nb
from nptyping import NDArray, Shape, Float


@nb.njit
def python_estimate_downside_risk(
ts: NDArray[Shape["*"], Float],
prices: NDArray[Shape["*"], Float],
ts: Annotated[NDArray[np.float64], Literal["1D array"]],
prices: Annotated[NDArray[np.float64], Literal["1D array"]],
target_return: float
) -> float:
"""Estimate the downside risk of an asset based on historical price data.
Expand Down Expand Up @@ -35,8 +37,8 @@ def python_estimate_downside_risk(

@nb.njit
def python_estimate_upside_risk(
ts: NDArray[Shape["*"], Float],
prices: NDArray[Shape["*"], Float],
ts: Annotated[NDArray[np.float64], Literal["1D array"]],
prices: Annotated[NDArray[np.float64], Literal["1D array"]],
target_return: float
) -> float:
"""Estimate the upside risk of an asset based on historical price data.
Expand Down
18 changes: 9 additions & 9 deletions src/finsim/estimate/risk.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@

from typing import Literal
from typing import Literal, Annotated

import numpy as np
from numpy.typing import NDArray
from scipy import stats
from nptyping import NDArray, Shape, Float, Datetime64

from .native.pyrisk import python_estimate_downside_risk, python_estimate_upside_risk
from .constants import dividing_factors_dict


def estimate_downside_risk(
timestamps: NDArray[Shape["*"], Datetime64],
prices: NDArray[Shape["*"], Float],
timestamps: Annotated[NDArray[np.datetime64], Literal["1D array"]],
prices: Annotated[NDArray[np.float64], Literal["1D array"]],
target_return: float,
unit: Literal['second', 'minute', 'hour', 'day', 'year']='year'
) -> float:
Expand Down Expand Up @@ -43,8 +43,8 @@ def estimate_downside_risk(


def estimate_upside_risk(
timestamps: NDArray[Shape["*"], Datetime64],
prices: NDArray[Shape["*"], Float],
timestamps: Annotated[NDArray[np.datetime64], Literal["1D array"]],
prices: Annotated[NDArray[np.float64], Literal["1D array"]],
target_return: float,
unit: Literal['second', 'minute', 'hour', 'day', 'year'] = 'year'
) -> float:
Expand Down Expand Up @@ -76,9 +76,9 @@ def estimate_upside_risk(


def estimate_beta(
timestamps: NDArray[Shape["*"], Datetime64],
prices: NDArray[Shape["*"], Float],
market_prices: NDArray[Shape["*"], Float],
timestamps: Annotated[NDArray[np.datetime64], Literal["1D array"]],
prices: Annotated[NDArray[np.float64], Literal["1D array"]],
market_prices: Annotated[NDArray[np.float64], Literal["1D array"]],
unit: Literal['second', 'minute', 'hour', 'day', 'year']='year'
) -> float:
"""Estimate the beta coefficient of an asset relative to market performance.
Expand Down
23 changes: 12 additions & 11 deletions src/finsim/portfolio/optimize/metrics.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@

from typing import Literal
from typing import Literal, Annotated

from nptyping import NDArray, Shape, Float
import numpy as np
from numpy.typing import NDArray

from .native.pymetrics import python_sharpe_ratio, python_mpt_costfunction, python_mpt_entropy_costfunction


def sharpe_ratio(
weights: NDArray[Shape["*"], Float],
r: NDArray[Shape["*"], Float],
cov: NDArray[Shape["*, *"], Float],
weights: Annotated[NDArray[np.float64], Literal["1D array"]],
r: Annotated[NDArray[np.float64], Literal["1D array"]],
cov: Annotated[NDArray[np.float64], Literal["2D array"]],
rf: float
) -> float:
"""Calculate the Sharpe ratio for a portfolio.
Expand All @@ -27,9 +28,9 @@ def sharpe_ratio(


def mpt_costfunction(
weights: NDArray[Shape["*"], Float],
r: NDArray[Shape["*"], Float],
cov: NDArray[Shape["*, *"], Float],
weights: Annotated[NDArray[np.float64], Literal["1D array"]],
r: Annotated[NDArray[np.float64], Literal["1D array"]],
cov: Annotated[NDArray[np.float64], Literal["2D array"]],
rf: float,
lamb: float,
V0: float=10.
Expand All @@ -52,9 +53,9 @@ def mpt_costfunction(


def mpt_entropy_costfunction(
weights: NDArray[Shape["*"], Float],
r: NDArray[Shape["*"], Float],
cov: NDArray[Shape["*, *"], Float],
weights: Annotated[NDArray[np.float64], Literal["1D array"]],
r: Annotated[NDArray[np.float64], Literal["1D array"]],
cov: Annotated[NDArray[np.float64], Literal["2D array"]],
rf: float,
lamb0: float,
lamb1: float,
Expand Down
22 changes: 12 additions & 10 deletions src/finsim/portfolio/optimize/native/pymetrics.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@

from typing import Literal, Annotated

import numpy as np
from numpy.typing import NDArray
import numba as nb
from nptyping import NDArray, Shape, Float


@nb.njit
def python_sharpe_ratio(
weights: NDArray[Shape["*"], Float],
r: NDArray[Shape["*"], Float],
cov: NDArray[Shape["*, *"], Float],
weights: Annotated[NDArray[np.float64], Literal["1D array"]],
r: Annotated[NDArray[np.float64], Literal["1D array"]],
cov: Annotated[NDArray[np.float64], Literal["2D array"]],
rf: float
) -> float:
"""Calculate the Sharpe ratio for a portfolio using Python/Numba.
Expand All @@ -30,9 +32,9 @@ def python_sharpe_ratio(

@nb.njit
def python_mpt_costfunction(
weights: NDArray[Shape["*"], Float],
r: NDArray[Shape["*"], Float],
cov: NDArray[Shape["*, *"], Float],
weights: Annotated[NDArray[np.float64], Literal["1D array"]],
r: Annotated[NDArray[np.float64], Literal["1D array"]],
cov: Annotated[NDArray[np.float64], Literal["2D array"]],
rf: float,
lamb: float,
V0: float=10.
Expand All @@ -57,9 +59,9 @@ def python_mpt_costfunction(

@nb.njit
def python_mpt_entropy_costfunction(
weights: NDArray[Shape["*"], Float],
r: NDArray[Shape["*"], Float],
cov: NDArray[Shape["*, *"], Float],
weights: Annotated[NDArray[np.float64], Literal["1D array"]],
r: Annotated[NDArray[np.float64], Literal["1D array"]],
cov: Annotated[NDArray[np.float64], Literal["2D array"]],
rf: float,
lamb0: float,
lamb1: float,
Expand Down
Loading