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
4,448 changes: 4,448 additions & 0 deletions src/quantlib_st/data/futures/multiple_prices_csv/RUBBER.csv

Large diffs are not rendered by default.

2,794 changes: 2,794 additions & 0 deletions src/quantlib_st/data/futures/multiple_prices_csv/SOFR.csv

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions src/quantlib_st/data/futures/roll_calendars_csv/RUBBER.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
DATE_TIME,current_contract,next_contract,carry_contract
2021-10-13 23:00:00,20211100,20211200,20211200
2021-11-01 23:00:00,20211200,20220100,20220100
2021-12-01 23:00:00,20220100,20220200,20220200
2021-12-30 23:00:00,20220200,20220300,20220300
2022-01-28 23:00:00,20220300,20220400,20220400
2022-03-01 23:00:00,20220400,20220500,20220500
2022-03-31 23:00:00,20220500,20220600,20220600
2022-04-29 23:00:00,20220600,20220700,20220700
2022-05-31 23:00:00,20220700,20220800,20220800
2022-07-01 23:00:00,20220800,20220900,20220900
2022-08-01 23:00:00,20220900,20221000,20221000
2022-08-31 23:00:00,20221000,20221100,20221100
2022-09-30 23:00:00,20221100,20221200,20221200
2022-10-12 23:00:00,20221200,20230100,20230100
4 changes: 3 additions & 1 deletion src/quantlib_st/estimators/vol.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@ def mixed_vol_calc(
**ignored_kwargs,
) -> pd.Series:
"""
Robust exponential volatility calculation, assuming daily series of prices
Blending short-term (robust) vol with a long-term slow vol component,
assuming daily series of prices.

We apply an absolute minimum level of vol (absmin);
and a volfloor based on lowest vol over recent history

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import pandas as pd

from typing import Literal, get_args

from quantlib_st.core.pandas.merge_data_with_label_column import (
merge_data_series_with_label_column,
)
Expand All @@ -10,13 +12,16 @@
price_name = "PRICE"
carry_name = "CARRY"
forward_name = "FORWARD"

price_column_names_literal = Literal["PRICE", "CARRY", "FORWARD"]

price_column_names = dict(CARRY=carry_name, PRICE=price_name, FORWARD=forward_name)
list_of_price_column_names = list(price_column_names.values())
list_of_price_column_names = list(get_args(price_column_names_literal))
list_of_price_column_names.sort()
contract_suffix = "_CONTRACT"


def contract_name_from_column_name(column_name):
def contract_name_from_column_name(column_name: price_column_names_literal) -> str:
return column_name + contract_suffix


Expand Down Expand Up @@ -48,37 +53,33 @@ def _check_key_list_is_valid_against_names(some_dict):
)


class futuresNamedContractFinalPricesWithContractID(pd.DataFrame):
class futuresNamedContractFinalPricesWithContractID:
"""
Just the final prices from a futures contract, plus
Columns are named 'NAME' and 'NAME_CONTRACT'
Just the final prices from a futures contract, plus contract IDs.
Encapsulates a pd.DataFrame with columns: [price_column_name, contract_column_name]
"""

def __init__(
self,
ts_of_prices: pd.Series,
ts_of_contracts: pd.Series,
price_column_name: str = list_of_price_column_names[0],
price_column_name: price_column_names_literal = "PRICE",
):
"""

:param price_and_contract_data: pd.DataFrame with two columns
:param column_name: column name for price
"""
assert price_column_name in list_of_price_column_names

price_and_contract_data = pd.concat([ts_of_prices, ts_of_contracts], axis=1)

df = pd.concat([ts_of_prices, ts_of_contracts], axis=1)
contract_column_name = price_column_name + contract_suffix
price_and_contract_data.columns = [price_column_name, contract_column_name]

super().__init__(price_and_contract_data)
df.columns = [price_column_name, contract_column_name]

self._price_column_name = price_column_name
self._df = df
self._price_column_name: price_column_names_literal = price_column_name
self._contract_column_name = contract_column_name

def __len__(self) -> int:
return len(self._df)

@property
def price_column_name(self) -> str:
def price_column_name(self) -> price_column_names_literal:
return self._price_column_name

@property
Expand All @@ -87,21 +88,21 @@ def contract_column_name(self) -> str:

@property
def prices(self) -> pd.Series:
return self[self.price_column_name]
return self._df[self.price_column_name]

@property
def ts_of_contract_str(self) -> pd.Series:
return self[self.contract_column_name]
return self._df[self.contract_column_name]

def as_pd(self):
return pd.DataFrame(self)
def as_pd(self) -> pd.DataFrame:
return self._df

@classmethod
def create_with_single_contractid(
futuresNamedContractFinalPricesWithContractID,
cls,
ts_of_prices: pd.Series,
contractid: str,
price_column_name=price_name,
price_column_name: price_column_names_literal = price_name,
):
"""

Expand All @@ -114,9 +115,7 @@ def create_with_single_contractid(
contract_data = [contractid] * len(ts_of_prices)
ts_of_contracts = pd.Series(contract_data, index=ts_of_prices.index)

return futuresNamedContractFinalPricesWithContractID(
ts_of_prices, ts_of_contracts, price_column_name=price_column_name
)
return cls(ts_of_prices, ts_of_contracts, price_column_name=price_column_name)

def prices_after_date(self, date_slice):
prices = self.prices[date_slice:]
Expand Down Expand Up @@ -179,8 +178,8 @@ def _merge_futures_contract_final_prices_with_contract_id(
contract_column_name = original_data.contract_column_name

merged_data_as_pd = merge_data_series_with_label_column(
original_data,
new_data,
original_data.as_pd(),
new_data.as_pd(),
data_column=price_column_name,
label_column=contract_column_name,
)
Expand Down Expand Up @@ -267,7 +266,7 @@ def __repr__(self):

@classmethod
def create_from_two_dicts(
dictFuturesNamedContractFinalPricesWithContractID,
cls,
dict_of_final_prices: dictNamedFuturesContractFinalPrices,
dict_of_contract_ids: setOfNamedContracts,
):
Expand All @@ -293,7 +292,7 @@ def create_from_two_dicts(
)
new_dict[key] = prices_with_contractid

return dictFuturesNamedContractFinalPricesWithContractID(new_dict)
return cls(new_dict)

def merge_data(self, new_price_dict):
"""
Expand Down
4 changes: 2 additions & 2 deletions src/quantlib_st/objects/instruments.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from quantlib_st.core.constants import arg_not_supplied
from quantlib_st.core.constants import arg_not_supplied, named_object
from quantlib_st.core.genutils import flatten_list

from dataclasses import dataclass
Expand Down Expand Up @@ -220,7 +220,7 @@ def as_pd(self) -> pd.Series:
return pd.Series(asset_classes, index=instruments)

def all_instruments_in_asset_class(
self, asset_class: str, must_be_in=arg_not_supplied
self, asset_class: str, must_be_in: list | named_object = arg_not_supplied
) -> list:
asset_class_instrument_list = [
instrument
Expand Down
19 changes: 10 additions & 9 deletions src/quantlib_st/objects/multiple_prices.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from copy import copy
from dataclasses import dataclass
from typing import Optional

import datetime as datetime
import pandas as pd
Expand Down Expand Up @@ -29,12 +30,12 @@

@dataclass
class singleRowMultiplePrices:
price: float = None
carry: float = None
forward: float = None
price_contract: str = None
carry_contract: str = None
forward_contract: str = None
price: Optional[float] = None
carry: Optional[float] = None
forward: Optional[float] = None
price_contract: Optional[str] = None
carry_contract: Optional[str] = None
forward_contract: Optional[str] = None

def concat_with_multiple_prices(self, multiple_prices, timedelta_seconds=1):
new_time_index = multiple_prices.index[-1] + datetime.timedelta(
Expand Down Expand Up @@ -70,7 +71,7 @@ def as_aligned_pd_row(self, time_index: datetime.timedelta) -> pd.DataFrame:
class futuresMultiplePrices(pd.DataFrame):
def __init__(self, data):
_check_valid_multiple_price_data(data)
super().__init__(data)
super().__init__(data) # type: ignore

data.index.name = "index" # arctic compatible

Expand Down Expand Up @@ -152,7 +153,7 @@ def as_dict(self) -> dictFuturesNamedContractFinalPricesWithContractID:
self[contract_column_name],
price_column_name=price_column_name,
)
)
) # type: ignore

self_as_dict = dictFuturesNamedContractFinalPricesWithContractID(self_as_dict)

Expand Down Expand Up @@ -194,7 +195,7 @@ def from_merged_dict(

return multiple_prices_object

def sort_index(self):
def sort_index(self): # type: ignore
df = pd.DataFrame(self)
sorted_df = df.sort_index()

Expand Down
2 changes: 1 addition & 1 deletion src/quantlib_st/sysdata/base_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def __getitem__(self, keyname):
"__getitem__ not defined for baseData class: use a class where it has been overridden"
)

def keys(self):
def keys(self) -> list[str]:
"""
list of things in this data set (futures contracts, instruments...)

Expand Down
4 changes: 4 additions & 0 deletions src/quantlib_st/sysdata/csv/csv_multiple_prices.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ def datapath(self):
return self._datapath

def get_list_of_instruments(self):
self.log.info(
"Getting list of instruments with multiple prices from path %s"
% self.datapath
)
return files_with_extension_in_pathname(self.datapath, ".csv")

def _get_multiple_prices_without_checking(
Expand Down
16 changes: 8 additions & 8 deletions src/quantlib_st/sysdata/data_blob.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
from typing import Any, TYPE_CHECKING

from quantlib_st.core.objects import get_class_name
from quantlib_st.core.constants import arg_not_supplied
from quantlib_st.core.constants import arg_not_supplied, named_object
from quantlib_st.core.fileutils import get_resolved_pathname
from quantlib_st.core.text import camel_case_split
from quantlib_st.logging.logger import get_logger
from quantlib_st.logging.adaptor import COMPONENT_LOG_LABEL
from quantlib_st.logging.adaptor import COMPONENT_LOG_LABEL, DynamicAttributeLogger

if TYPE_CHECKING:
from quantlib_st.sysdata.production_config import Config # pragma: no cover
Expand All @@ -23,13 +23,13 @@
class dataBlob(object):
def __init__(
self,
class_list: list = arg_not_supplied,
class_list: list | named_object = arg_not_supplied,
log_name: str = "",
csv_data_paths: dict = arg_not_supplied,
parquet_store_path: str = arg_not_supplied,
csv_data_paths: dict[str, str] | named_object = arg_not_supplied,
parquet_store_path: str | named_object = arg_not_supplied,
ib_conn: Any = arg_not_supplied,
mongo_db: Any = arg_not_supplied,
log=arg_not_supplied,
log: DynamicAttributeLogger | named_object = arg_not_supplied,
keep_original_prefix: bool = False,
):
"""
Expand Down Expand Up @@ -188,7 +188,7 @@ def _add_csv_class(self, class_object):

return resolved_instance

def _get_csv_paths_for_class(self, class_object) -> str:
def _get_csv_paths_for_class(self, class_object) -> str | named_object:
class_name = get_class_name(class_object)
csv_data_paths = self.csv_data_paths
if csv_data_paths is arg_not_supplied:
Expand All @@ -205,7 +205,7 @@ def _get_csv_paths_for_class(self, class_object) -> str:
return datapath

@property
def csv_data_paths(self) -> dict:
def csv_data_paths(self) -> dict | named_object:
csv_data_paths = getattr(self, "_csv_data_paths", arg_not_supplied)

return csv_data_paths
Expand Down
12 changes: 9 additions & 3 deletions src/quantlib_st/sysdata/sim/csv_futures_sim_test_data.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import pandas as pd
from datetime import datetime
from typing import Optional

from quantlib_st.sysdata.csv.csv_multiple_prices import csvFuturesMultiplePricesData
from quantlib_st.sysdata.csv.csv_adjusted_prices import csvFuturesAdjustedPricesData
Expand Down Expand Up @@ -33,13 +34,18 @@ class CsvFuturesSimTestData(genericBlobUsingFuturesSimData):
DEFAULT_END_DATE = datetime.strptime("2021-03-08 20:00:00", DATE_FORMAT)

def __init__(
self, start_date=None, end_date=None, log=get_logger("csvFuturesSimTestData")
self,
start_date: Optional[datetime] = None,
end_date: Optional[datetime] = None,
log=get_logger("csvFuturesSimTestData"),
):
data = dataBlob(
log=log,
csv_data_paths=dict(
csvFuturesAdjustedPricesData="quantlib_st.data.test.adjusted_prices_csv",
csvFuturesInstrumentData="quantlib_st.data.test.csvconfig",
csvFuturesMultiplePricesData="quantlib_st.data.futures.multiple_prices_csv",
csvRollParametersData="quantlib_st.data.futures.roll_calendars_csv",
csvSpreadCostData="quantlib_st.data.test.csvconfig",
),
class_list=[
Expand Down Expand Up @@ -86,7 +92,7 @@ def get_backadjusted_futures_price(
instrument_code
)
date_adjusted = data[self.start_date : self.end_date]
return date_adjusted
return date_adjusted # type: ignore

def get_multiple_prices(self, instrument_code: str) -> futuresMultiplePrices:
data = super().get_multiple_prices(instrument_code)
Expand All @@ -98,7 +104,7 @@ def get_fx_for_instrument(
) -> fxPrices:
data = super().get_fx_for_instrument(instrument_code, base_currency)
date_adjusted = data[self.start_date : self.end_date]
return date_adjusted
return date_adjusted # type: ignore

def daily_prices(self, instrument_code: str) -> pd.Series:
data = super().daily_prices(instrument_code)
Expand Down
Loading