Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New version: v.1.2.0 #6

Open
wants to merge 28 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
b2a1ce5
inc version to 1.1.2
0xfdf Aug 10, 2024
ac17f09
better example of show_versions
0xfdf Aug 10, 2024
7ffdec3
implement basic issue templates for github organization
0xfdf Aug 11, 2024
d4a080a
more documentation of the momentum factor, and add more optionality
0xfdf Aug 11, 2024
54c0bbc
add flexibility to pass custom column names as arguments
0xfdf Aug 11, 2024
8598b33
add new columns to docs while I wait for a run
0xfdf Aug 11, 2024
b72bf56
looks like this will become a 1.2 release; more flexibility; rounded …
0xfdf Aug 11, 2024
aa4b13a
allow users to pass their own column names for the `estimate_factor_r…
0xfdf Aug 11, 2024
4c61589
significantly better documentation on the core model functions
0xfdf Aug 11, 2024
470ff25
map_groups is significantly faster (on 2000 assets over 10 years, it …
0xfdf Aug 11, 2024
c198715
to ensure backwards compat, put back lower and upper deciles
0xfdf Aug 11, 2024
85d4db2
inc version to 1.2.0 to reflect significant feature enhancements unde…
0xfdf Aug 11, 2024
869ff7c
add logging on center vs standardize nuance in style factors
0xfdf Aug 11, 2024
1e4ef3f
create a config file
0xfdf Aug 11, 2024
2eacd05
initial implementations of ledoit-wolf and sftu shrinkage
0xfdf Aug 11, 2024
52997c0
create dummies is implemented and fully tested
0xfdf Aug 11, 2024
65f1cb1
full documentation of config options
0xfdf Aug 11, 2024
b42b2bf
fully document types in the config.ini
0xfdf Aug 11, 2024
8a0839f
implement config system
0xfdf Aug 12, 2024
16f9444
test turning on more of the style factors
0xfdf Aug 12, 2024
db32d02
Update math.py
0xfdf Aug 12, 2024
e842e4c
rounded out an mvp of the FactorModel class
0xfdf Aug 13, 2024
3ecb480
fix merge
0xfdf Aug 13, 2024
898cdba
Merge branch 'v1.1.2' of ssh://github.com/0xfdf/toraniko into v1.1.2
0xfdf Aug 13, 2024
f4e4457
make the inputs lazy proactively
0xfdf Aug 13, 2024
4889cdc
use collect_schema().names() instead of .columns for perf enhancement
0xfdf Aug 14, 2024
e212f3d
add logic to drop_nans_and_nulls; also part out the nan_to_null lgoic…
0xfdf Aug 15, 2024
ace86d2
implement rolling covariance so we can use ledoit_wolf for idio cov p…
0xfdf Aug 16, 2024
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
63 changes: 63 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: '🐞 Bug report'
description: Report a bug that needs fixing.
labels: [bug, needs triage]

body:
- type: checkboxes
id: checks
attributes:
label: Checks
options:
- label: I have checked that this issue has not already been reported.
required: true
- label: I have confirmed this bug exists on the [latest version](https://pypi.org/project/toraniko/) of Toraniko.
required: true

- type: textarea
id: example
attributes:
label: Reproducible example
description: >
Please follow [this guide](https://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports) on how to
provide a minimal, copy-pasteable example. Include the (wrong) output if applicable.
value: |
```python

```
validations:
required: true

- type: textarea
id: problem
attributes:
label: Issue description
description: >
Provide any additional information you think might be relevant.
validations:
required: true

- type: textarea
id: expected-behavior
attributes:
label: Expected behavior
description: >
Describe or show a code example of the expected behavior.
validations:
required: true

- type: textarea
id: version
attributes:
label: Installed versions
description: >
Paste the output of ``toraniko.show_versions()``
value: |
<details>

```
Replace this line with the output of toraniko.show_versions(). Leave the backticks in place.
```

</details>
validations:
required: true
14 changes: 14 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
name: '✨ Feature request'
description: Suggest a new feature or enhancement for Toraniko.
labels: [enhancement]

body:
- type: textarea
id: description
attributes:
label: Description
description: >
Describe the feature or enhancement and explain why it should be implemented.
Include a code example if applicable.
validations:
required: true
19 changes: 16 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
# toraniko
# Toraniko: Multi-factor risk models for quantitative trading

Toraniko is a complete implementation of a risk model suitable for quantitative and systematic trading at institutional scale. In particular, it is a characteristic factor model in the same vein as Barra and Axioma (in fact, given the same datasets, it approximately reproduces Barra's estimated factor returns).
Toraniko is a complete implementation of a risk model suitable for quantitative and systematic trading at institutional scale. In particular, it is a characteristic factor model in the same vein as Barra and Axioma (in fact, given the same inputs, it approximately reproduces Barra's estimated factor returns).

![mom_factor](https://github.com/user-attachments/assets/f9d2927c-e899-4fd6-944c-8f9a104b410f)

Using this library, you can create new custom factors and estimate their returns. Then you can estimate a factor covariance matrix suitable for portfolio optimization with factor exposure constraints (e.g. to main a market neutral portfolio).

The only dependencies are numpy and polars. It supports market, sector and style factors; three styles are included: value, size and momentum. The library also comes with generalizable math and data cleaning utility functions you'd want to have for constructing more style factors (or custom fundamental factors of any kind).

## Advantages

- features: style/custom factor score construction, return estimation, factor covariance estimation with shrinkage
- fast
- fully tested
- few dependencies: only numpy and polars. all mathematical and statistical primitives are implemented in the library
- config-driven
- generalized function for rapid custom factor construction

## Installation

Using pip:
First install using pip:

`pip install toraniko`

Then you can optionally create a config directory with `toraniko-init` in your command line.

## User Manual

#### Data
Expand Down Expand Up @@ -182,3 +193,5 @@ Here is a comparison of the model value factor out versus Barra's. Even on a rel
![val_factor](https://github.com/user-attachments/assets/28f41989-f802-4c2f-beed-1d2bda24a96d)

![valu](https://github.com/user-attachments/assets/366f49a8-d7e7-46de-bb61-6f656393275a)

## Limitations
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "toraniko"
version = "1.1.0"
version = "1.2.0"
description = "A multi-factor equity risk model for quantitative trading."
authors = ["0xfdf <[email protected]>"]
maintainers = ["0xfdf <[email protected]>"]
Expand Down Expand Up @@ -45,3 +45,6 @@ select = ["E", "F", "I", "N", "Q", "R", "S", "T", "U", "W", "Y"]

[tool.black]
line-length = 120

[tool.poetry.scripts]
toraniko-init = "toraniko.config:init_config"
6 changes: 3 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from setuptools import setup, find_packages

requirements = []
with open('requirements.txt', 'r') as fh:
with open("requirements.txt", "r") as fh:
for line in fh:
requirements.append(line.strip())

setup(
name="toraniko",
version="1.1.0",
version="1.2.0",
packages=find_packages(),
install_requires = requirements
install_requires=requirements,
)
69 changes: 69 additions & 0 deletions toraniko/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from __future__ import annotations

import sys

__title__ = "toraniko"

__description__ = "A multi-factor equity risk model for quantitative trading."

__version__ = "1.2.0"


# Credit to Ritchie Vink and Polars: this implementation comes almost directly from
# https://github.com/pola-rs/polars/blob/main/py-polars/polars/meta/versions.py
def show_versions() -> None:
"""
Print out the version of Toraniko and its optional dependencies.

Examples
--------
>>> toraniko.show_versions()
--------Version info---------
Toraniko: 1.1.2
Platform: macOS-14.5-arm64-arm-64bit
Python: 3.11.9 (main, Apr 19 2024, 11:43:47) [Clang 14.0.6 ]

----Optional dependencies----
numpy: 1.26.4
polars: 1.0.0
""" # noqa: W505
# Note: we import 'platform' here (rather than at the top of the
# module) as a micro-optimization for polars' initial import
import platform

deps = _get_dependency_info()
core_properties = ("Toraniko", "Platform", "Python")
keylen = max(len(x) for x in [*core_properties, *deps.keys()]) + 1

print("--------Version info---------")
print(f"{'Toraniko:':{keylen}s} {__version__}")
print(f"{'Platform:':{keylen}s} {platform.platform()}")
print(f"{'Python:':{keylen}s} {sys.version}")

print("\n----Optional dependencies----")
for name, v in deps.items():
print(f"{name:{keylen}s} {v}")


def _get_dependency_info() -> dict[str, str]:
# see the list of dependencies in pyproject.toml
opt_deps = ["numpy", "polars"]
return {f"{name}:": _get_dependency_version(name) for name in opt_deps}


def _get_dependency_version(dep_name: str) -> str:
# note: we import 'importlib' here as a significant optimisation for initial import
import importlib
import importlib.metadata

try:
module = importlib.import_module(dep_name)
except ImportError:
return "<not installed>"

if hasattr(module, "__version__"):
module_version = module.__version__
else:
module_version = importlib.metadata.version(dep_name) # pragma: no cover

return module_version
118 changes: 118 additions & 0 deletions toraniko/config.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#####
###
# Toraniko Model Config
#
# Don't remove any settings in this file! Only edit the settings you want to change.
# Be mindful of types. Use null to turn off settings marked as optional.
###
#####

###
# Standardized column names
###

[global_column_names]
# string column name to expect assert returns in
asset_returns_col = asset_returns
# string column name to expect symbol names in
symbol_col = symbol
# string column name to expect time period values in
date_col = date
# string column name to expect market cap values in
mkt_cap_col = market_cap
# string column name to expect sector encodings in
sectors_col = sector

###
# Complete model estimation settings
###

[model_estimation]
# optional float symmetric percentile for winsorizing returns. pass null to turn off
winsor_factor = 0.02
# boolean indicating if style factors be residualized against the sector and market factors
residualize_styles = false
# string column name to return market factor returns under
mkt_factor_col = Market
# string column name to return asset residual returns under
res_ret_col = res_asset_returns
# optional integer max number of assets to include in each time period, as sorted by market cap desc. pass null for off
top_n_by_mkt_cap = 2000
# string proxy to use for the asset idio covariance during factor estimation: may be 'market_caps' or 'ledoit_wolf'
proxy_for_idio_cov = market_cap
# boolean indicating if the `sector_scores` are already dummy variables or if they need to be transformed to such
make_sector_dummies = true
# optional list of strings indicating whether to clean each feature column via fill forward. pass null or empty for off
fill_features = null
# optional dict of string column name: int smooth window pairs to control feature smoothing. pass null for off
smooth_features = {'market_cap': 20}


###
# Style factor settings
###

[style_factors.mom]
# boolean indicating if the factor is turned on. if false, factor scores will not be estimated or included in model
enabled = true
# integer number of trailing time periods used to calculate the cumulative return
trailing_days = 252
# integer number of trailing time periods used for the half-life decay on the exponential weighting of returns
half_life = 126
# integer number of the most recent trailing time periods to preclude from consideration for any time t
lag = 20
# optional float symmetric percentile, to use for winsorization of the momentum scores. pass null for off
winsor_factor = 0.01
# boolean indicating if final scores should be centered
center = true
# boolean indicating if final scored should be standardized
standardize = true
# string column name to return momentum scores under
score_col = mom_score

[style_factors.sze]
# boolean indicating if the factor is turned on. if false, factor scores will not be estimated or included in model
enabled = true
# optional float value to be used for the lower_decile percentile. pass null for off
lower_decile = null
# optional float value to be used for the upper decile percentile. pass null for off
upper_decile = null
# boolean indicating if final scores should be centered
center = true
# boolean indicating if final scored should be standardized
standardize = true
# string column name to return size scores under
score_col = sze_score

[style_factors.val]
# boolean indicating if the factor is turned on. if false, factor scores will not be estimated or included in model
enabled = true
# optional float symmetric percentile, to use for winsorization of the value scores. pass null for off
winsor_factor = null
# boolean indicating if final scores should be centered
center = true
# boolean indicating if final scored should be standardized
standardize = true
# string column name to look for book-price ratios in
bp_col = book_price
# string column name to look for sales-price ratios in
sp_col = sales_price
# string column name to look for cash flow-price ratios in
cf_col = cf_price
# string column name to return value scores under
score_col = val_score

###
# Custom factor settings
###

# this section only exists to show an example custom factor config
[custom_factors.test]
name = test
enabled = false
feature_cols = []
center = true
standardize = true
score_col = test_score


Loading
Loading