Skip to content

Commit 16e79bf

Browse files
committed
Change to_csv param 'get_params' for **kwargs
Also adds `to_csv` to `other_prices_methods.ipynb` tutorial.
1 parent 766caa9 commit 16e79bf

File tree

4 files changed

+132
-30
lines changed

4 files changed

+132
-30
lines changed

docs/tutorials/other_prices_methods.ipynb

Lines changed: 111 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
"source": [
1414
"#### Sections\n",
1515
"* [`request_all_prices`](#request_all_prices)\n",
16-
"* [`prices_for_symbols`](#prices_for_symbols)"
16+
"* [`prices_for_symbols`](#prices_for_symbols)\n",
17+
"* [`to_csv`](#to_csv)"
1718
]
1819
},
1920
{
@@ -135,7 +136,7 @@
135136
"source": [
136137
"Notice that no prices are stored for the H1 interval. This is because prices include an equity listed on the New York Stock Exchange and one listed on the London Stock Exchange. The opening times of these exchanges are such that sessions often overlap although the indices at H1 are not aligned. Consequently, it's not possible to evaluate common hourly indices (at least not using H1 data).\n",
137138
"\n",
138-
"The rest of this subsection demonstrates some under-the-bonnet behaviour that can be safely skipped - move onto [`prices_for_symbols`](#prices_for_symbols) if you're not interested.\n",
139+
"The rest of this section demonstrates some under-the-bonnet behaviour that can be safely skipped - move onto [`prices_for_symbols`](#prices_for_symbols) if you're not interested.\n",
139140
"\n",
140141
"Srictly speaking, valid hourly data will be available for any session where only one of these two exchanges is open, or when one or both have irregular opening hours such that they do not overlap (or align if they do). If intraday prices are requested for just such a session then a request for hourly data will be sent to the provider if intraday prices for that session are not available at an interval smaller than one hour."
141142
]
@@ -729,13 +730,118 @@
729730
"source": [
730731
"new_prices._pdata[new_prices.bis.T5]._table"
731732
]
733+
},
734+
{
735+
"cell_type": "markdown",
736+
"metadata": {},
737+
"source": [
738+
"## `to_csv`\n",
739+
"`to_csv` provides for exporting price data to .csv files. The method has one required argument 'path' which takes a path to an **existing** directory to which the .csv files should be written. If no further arguments are passed then the default implementation will export all available price data as one csv file per aligned base interval per symbol, such that if there are 3 base intervals and 5 symbols then 15 .csv files will be created (the base intervals for a prices instance can be inspected with `prices.bis.__members__`).\n",
740+
"\n",
741+
"Optional arguments provide for defining the `intervals` for which price data should be exported together with which symbols to `include` or `exclude`. The period over which price data is to be exported and the configuration of that data can be defined by passing any kwargs that are accepted by the `get` method (with the exception of 'interval'). For example 'start', 'days', 'anchor', 'priority', 'strict' etc are all valid keyword arguments.\n",
742+
"\n",
743+
"Files exported with `to_csv` can be retrieved with the default implementation of the `PricesCsv` class. (NB this requires that the exported data conforms with the requirements of the `PricesCsv` class, for example that prices are anchored on the 'open' and have an interval no higher than daily. Files exported with the default implementation will always be retrievable via the `PricesCsv` class.)\n",
744+
"\n",
745+
"See the method doc for further information..."
746+
]
747+
},
748+
{
749+
"cell_type": "code",
750+
"execution_count": null,
751+
"metadata": {},
752+
"outputs": [],
753+
"source": [
754+
"prices.to_csv?"
755+
]
756+
},
757+
{
758+
"cell_type": "markdown",
759+
"metadata": {},
760+
"source": [
761+
"```\n",
762+
"Signature:\n",
763+
"prices.to_csv(\n",
764+
" path: 'Annotated[Union[str, Path], Coerce(Path), Parser(parsing.verify_directory)]',\n",
765+
" intervals: 'Optional[Union[str, pd.Timedelta, datetime.timedelta, list[str], list[pd.Timedelta], list[datetime.timedelta]]]' = None,\n",
766+
" include: 'Optional[mptypes.Symbols]' = None,\n",
767+
" exclude: 'Optional[mptypes.Symbols]' = None,\n",
768+
" **kwargs,\n",
769+
") -> 'list[Path]'\n",
770+
"Docstring:\n",
771+
"Export price data to .csv file(s).\n",
772+
"\n",
773+
"Note: Exported price data can be retrieved with the default\n",
774+
"implementation of the `PricesCsv` class (requires that the\n",
775+
"exported data conforms with the requirements of the\n",
776+
"`PricesCsv` class, for example that prices are anchored on\n",
777+
"the 'open' and have an interval no higher than daily).\n",
778+
"\n",
779+
"Price data will be exported by symbol by interval, such that if\n",
780+
"data is requested for 3 intervals and 5 symbols then 15 .csv\n",
781+
"files will be created.\n",
782+
"\n",
783+
".csv filenames will follow the format:\n",
784+
" <SYMBOL>_<INTERVAL>_<YYMMDD>_<YYMMDD>.csv\n",
785+
" For example:\n",
786+
" MSFT_5T_240122_240215.csv\n",
787+
" This file would hold '5T' (i.e. 5 minute) price data for\n",
788+
" the symbol MSFT covering the period from 2024-01-22 through\n",
789+
" 2024-02-15. Note: for intraday intervals the dates will\n",
790+
" represent the earliest and latest sessions for which at least\n",
791+
" some price data is included.\n",
792+
"\n",
793+
"Parameters\n",
794+
"----------\n",
795+
"path\n",
796+
" Directory to which .csv files should be written. This path\n",
797+
" must exist.\n",
798+
"\n",
799+
"intervals\n",
800+
" Intervals for which price data is to be exported. To define\n",
801+
" a single interval pass as for the 'interval` parameter of the\n",
802+
" `.get` method. To define multiple intervals pass as a list\n",
803+
" of one of the types that's acceptable input to the 'interval`\n",
804+
" parameter of the `.get` method.\n",
805+
"\n",
806+
" By default (None) .csv files are exported for all available\n",
807+
" base intervals.\n",
808+
"\n",
809+
"include : list[str] | str | None\n",
810+
" Symbol or symbols to include in export. All other symbols will\n",
811+
" be excluded. If passed, do not pass `exclude`.\n",
812+
"\n",
813+
" By default, if neither include nor exclude are passed then data\n",
814+
" will be exported for all symbols.\n",
815+
"\n",
816+
"exclude : list[str] | str | None\n",
817+
" Symbol or symbols to exclude from export. Data will be exported\n",
818+
" for all other symbols. If passed, do not pass `include`.\n",
819+
"\n",
820+
" By default, if neither exclude nor include are passed then data\n",
821+
" will be exported for all symbols.\n",
822+
"\n",
823+
"kwargs\n",
824+
" All other kwargs will be passed on to the `.get` method to\n",
825+
" define the period over which prices are to be exported. Can\n",
826+
" include other options, for example 'anchor', 'priority',\n",
827+
" 'strict' etc.\n",
828+
"\n",
829+
" If no other kwargs are not passed then by default all available\n",
830+
" data will be exported for each requested symbol / interval.\n",
831+
"\n",
832+
"Returns\n",
833+
"-------\n",
834+
"paths\n",
835+
" List of Path objects to which data exported.\n",
836+
"```"
837+
]
732838
}
733839
],
734840
"metadata": {
735841
"kernelspec": {
736-
"display_name": "mkt_prices 3.8.2",
842+
"display_name": "market_prices_ve_39",
737843
"language": "python",
738-
"name": "mkt_prices"
844+
"name": "market_prices_ve_39"
739845
},
740846
"language_info": {
741847
"codemirror_mode": {
@@ -747,7 +853,7 @@
747853
"name": "python",
748854
"nbconvert_exporter": "python",
749855
"pygments_lexer": "ipython3",
750-
"version": "3.8.2"
856+
"version": "3.9.13"
751857
},
752858
"widgets": {
753859
"application/vnd.jupyter.widget-state+json": {

src/market_prices/prices/base.py

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5122,7 +5122,7 @@ def to_csv(
51225122
] = None,
51235123
include: Optional[mptypes.Symbols] = None,
51245124
exclude: Optional[mptypes.Symbols] = None,
5125-
get_params: Optional[dict] = None,
5125+
**kwargs,
51265126
) -> list[Path]:
51275127
"""Export price data to .csv file(s).
51285128
@@ -5176,23 +5176,20 @@ def to_csv(
51765176
By default, if neither exclude nor include are passed then data
51775177
will be exported for all symbols.
51785178
5179-
get_params
5180-
Dictionary of parameters to be passed on to the `.get` method
5181-
to define the period over which prices are to be exported. Can
5179+
kwargs
5180+
All other kwargs will be passed on to the `.get` method to
5181+
define the period over which prices are to be exported. Can
51825182
include other options, for example 'anchor', 'priority',
51835183
'strict' etc.
51845184
5185-
If not passed then by default all available data will be
5186-
exported for each requested symbol / interval.
5185+
If no other kwargs are not passed then by default all available
5186+
data will be exported for each requested symbol / interval.
51875187
51885188
Returns
51895189
-------
51905190
paths
51915191
List of Path objects to which data exported.
51925192
"""
5193-
# NOTE If / when valimp supports **kwargs then the 'get_params'
5194-
# parameter could be changed to **kwargs (more convenient for client).
5195-
51965193
if TYPE_CHECKING:
51975194
assert isinstance(path, Path)
51985195

@@ -5204,18 +5201,16 @@ def to_csv(
52045201
else:
52055202
intervals_ = [to_ptinterval(intervals)]
52065203

5207-
if get_params is not None and "lose_single_symbol" in get_params:
5208-
get_params["lose_single_symbol"] = False
5204+
if kwargs.get("lose_single_symbol", False):
5205+
kwargs["lose_single_symbol"] = False
52095206

52105207
dfs = {}
52115208
for intrvl in intervals_:
5212-
if get_params is not None:
5209+
if kwargs:
52135210
try:
5214-
df = self.get(
5215-
intrvl, include=include, exclude=exclude, **get_params
5216-
)
5211+
df = self.get(intrvl, include=include, exclude=exclude, **kwargs)
52175212
except Exception as err:
5218-
raise errors.PricesUnavailableForExport(intrvl, get_params) from err
5213+
raise errors.PricesUnavailableForExport(intrvl, kwargs) from err
52195214
else:
52205215
try:
52215216
df = self.get(

tests/test_base_prices.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6368,18 +6368,18 @@ def assert_output_as_original_files(paths: list[Path]):
63686368
df_reloaded = df_reloaded[df_reloaded.columns.sort_values()]
63696369
assert_frame_equal(df, df_reloaded)
63706370

6371-
# verify can pass get_params
6371+
# verify can pass kwargs
63726372
clean_temp_test_dir()
6373-
get_params = {"start": df.index[7].right, "end": df.index[-7].left}
6374-
paths = prices.to_csv(temp_dir, "5T", get_params=get_params)
6373+
kwargs = {"start": df.index[7].right, "end": df.index[-7].left}
6374+
paths = prices.to_csv(temp_dir, "5T", **kwargs)
63756375
assert len(paths) == 3
63766376
prices_reloaded = csv.PricesCsv(temp_dir, symbols, calendars)
63776377
df_reloaded = prices_reloaded.get("5T")
63786378
assert df_reloaded.pt.interval == prices.bis.T5
6379-
assert df_reloaded.pt.first_ts == get_params["start"]
6380-
assert df_reloaded.pt.last_ts == get_params["end"]
6379+
assert df_reloaded.pt.first_ts == kwargs["start"]
6380+
assert df_reloaded.pt.last_ts == kwargs["end"]
63816381

6382-
# verify raises when no get_params
6382+
# verify raises when no kwargs
63836383
clean_temp_test_dir()
63846384
match = re.escape(
63856385
"It was not possible to export prices as an error was raised when prices were"
@@ -6390,8 +6390,8 @@ def assert_output_as_original_files(paths: list[Path]):
63906390
prices.to_csv(temp_dir, include=["NOT_A_SYMBOL"])
63916391
assert not list(temp_dir.iterdir())
63926392

6393-
# verify raises when pass get_params
6394-
get_params = {"start": df.pt.first_ts - (one_day * 7)}
6393+
# verify raises when pass kwargs
6394+
kwargs = {"start": df.pt.first_ts - (one_day * 7)}
63956395
match = re.escape(
63966396
"It was not possible to export prices as an error was raised when"
63976397
f" prices were requested for interval {TDInterval.T5}. The error is included at"
@@ -6400,5 +6400,5 @@ def assert_output_as_original_files(paths: list[Path]):
64006400
"\nNB prices have not been exported for any interval."
64016401
)
64026402
with pytest.raises(errors.PricesUnavailableForExport, match=match):
6403-
prices.to_csv(temp_dir, "5T", get_params=get_params)
6403+
prices.to_csv(temp_dir, "5T", **kwargs)
64046404
assert not list(temp_dir.iterdir())

tests/test_yahoo.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
# ...sessions that yahoo temporarily fails to return prices for if (seemingly)
4949
# send a high frequency of requests for prices from the same IP address.
5050
_flakylist = (
51+
pd.Timestamp("2024-01-21"),
5152
pd.Timestamp("2023-09-08"),
5253
pd.Timestamp("2023-09-01"),
5354
pd.Timestamp("2023-07-17"),

0 commit comments

Comments
 (0)