pwb-toolbox 0.1.3__tar.gz → 0.1.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pwb_toolbox-0.1.3 → pwb_toolbox-0.1.5}/PKG-INFO +1 -1
- {pwb_toolbox-0.1.3 → pwb_toolbox-0.1.5}/pwb_toolbox/datasets/__init__.py +105 -42
- {pwb_toolbox-0.1.3 → pwb_toolbox-0.1.5}/pwb_toolbox.egg-info/PKG-INFO +1 -1
- {pwb_toolbox-0.1.3 → pwb_toolbox-0.1.5}/setup.cfg +1 -1
- {pwb_toolbox-0.1.3 → pwb_toolbox-0.1.5}/LICENSE.txt +0 -0
- {pwb_toolbox-0.1.3 → pwb_toolbox-0.1.5}/README.md +0 -0
- {pwb_toolbox-0.1.3 → pwb_toolbox-0.1.5}/pwb_toolbox/__init__.py +0 -0
- {pwb_toolbox-0.1.3 → pwb_toolbox-0.1.5}/pwb_toolbox.egg-info/SOURCES.txt +0 -0
- {pwb_toolbox-0.1.3 → pwb_toolbox-0.1.5}/pwb_toolbox.egg-info/dependency_links.txt +0 -0
- {pwb_toolbox-0.1.3 → pwb_toolbox-0.1.5}/pwb_toolbox.egg-info/requires.txt +0 -0
- {pwb_toolbox-0.1.3 → pwb_toolbox-0.1.5}/pwb_toolbox.egg-info/top_level.txt +0 -0
- {pwb_toolbox-0.1.3 → pwb_toolbox-0.1.5}/pyproject.toml +0 -0
@@ -627,7 +627,9 @@ def load_dataset(
|
|
627
627
|
return df
|
628
628
|
|
629
629
|
|
630
|
-
def __convert_indices_to_usd(
|
630
|
+
def __convert_indices_to_usd(
|
631
|
+
df_indices: pd.DataFrame, df_forex: pd.DataFrame
|
632
|
+
) -> pd.DataFrame:
|
631
633
|
mapping = {
|
632
634
|
"ADSMI": "AED", # United Arab Emirates
|
633
635
|
"AEX": "EUR", # Netherlands
|
@@ -727,32 +729,40 @@ def __convert_indices_to_usd(df_indices, df_forex):
|
|
727
729
|
"SX5E": "EUR", # Europe
|
728
730
|
"TA125": "ILS", # Israel
|
729
731
|
}
|
730
|
-
symbols = df_indices.symbol.unique()
|
731
|
-
mapping = {k: v for k, v in mapping.items() if k in symbols}
|
732
732
|
frames = []
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
733
|
+
|
734
|
+
# iterate over the symbols that actually exist in df_indices
|
735
|
+
for symbol in df_indices["symbol"].unique():
|
736
|
+
df_idx = df_indices[df_indices["symbol"] == symbol].copy()
|
737
|
+
|
738
|
+
# 1) Figure out what currency the index is quoted in.
|
739
|
+
ccy = mapping.get(symbol) # None if not mapped
|
740
|
+
if ccy is None or ccy == "USD":
|
741
|
+
# Unknown or already USD – just keep the original rows
|
742
|
+
frames.append(df_idx)
|
737
743
|
continue
|
738
|
-
|
739
|
-
|
744
|
+
|
745
|
+
# 2) Find the matching FX rate (home-ccy → USD)
|
746
|
+
pair = ccy + "USD"
|
747
|
+
df_fx = df_forex[df_forex["symbol"] == pair].copy()
|
748
|
+
|
749
|
+
if df_idx.empty or df_fx.empty:
|
750
|
+
# No FX data – keep raw index levels instead of dropping them
|
751
|
+
frames.append(df_idx)
|
740
752
|
continue
|
741
|
-
# Merge dataframes on the date column
|
742
|
-
merged_df = pd.merge(
|
743
|
-
df_index, df_forex_currency, on="date", suffixes=("", "_forex")
|
744
|
-
)
|
745
753
|
|
746
|
-
#
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
merged_df["close"] = merged_df["close"] * merged_df["close_forex"]
|
754
|
+
# 3) Merge on date and convert OHLC
|
755
|
+
merged = pd.merge(df_idx, df_fx, on="date", suffixes=("", "_fx"))
|
756
|
+
for col in ("open", "high", "low", "close"):
|
757
|
+
merged[col] = merged[col] * merged[f"{col}_fx"]
|
751
758
|
|
752
|
-
frames.append(
|
759
|
+
frames.append(merged[["symbol", "date", "open", "high", "low", "close"]])
|
753
760
|
|
754
|
-
|
755
|
-
|
761
|
+
if not frames:
|
762
|
+
return pd.DataFrame(columns=df_indices.columns)
|
763
|
+
|
764
|
+
# Combine everything back into one DataFrame
|
765
|
+
return pd.concat(frames, ignore_index=True)
|
756
766
|
|
757
767
|
|
758
768
|
def __extract_years_to_maturity(bond_symbol):
|
@@ -861,37 +871,90 @@ def __extend_etfs(df_etfs):
|
|
861
871
|
return df
|
862
872
|
|
863
873
|
|
874
|
+
ALLOWED_FIELDS = {"open", "high", "low", "close"}
|
875
|
+
|
876
|
+
|
864
877
|
def get_pricing(
|
865
878
|
symbol_list,
|
866
|
-
fields=
|
879
|
+
fields=None, # ← default set below
|
867
880
|
start_date="1980-01-01",
|
868
881
|
end_date=date.today().isoformat(),
|
869
882
|
extend=False,
|
883
|
+
keep_single_level=True, # backward-compat flag
|
870
884
|
):
|
871
885
|
"""
|
872
|
-
|
886
|
+
Fetch OHLC pricing for the requested symbols.
|
887
|
+
|
888
|
+
Parameters
|
889
|
+
----------
|
890
|
+
symbol_list : str | list[str]
|
891
|
+
One ticker or a list of tickers.
|
892
|
+
fields : list[str] | None
|
893
|
+
Any subset of ["open", "high", "low", "close"].
|
894
|
+
Defaults to ["close"] for backward compatibility.
|
895
|
+
start_date, end_date : str (YYYY-MM-DD)
|
896
|
+
Slice the date index (inclusive).
|
897
|
+
extend : bool
|
898
|
+
Pass-through to `load_dataset(..., extend=extend)`.
|
899
|
+
keep_single_level : bool
|
900
|
+
If `True` and only one field is requested, flatten the columns so the
|
901
|
+
output matches the old behaviour (columns = symbols). If `False`
|
902
|
+
you always get a two-level MultiIndex `(symbol, field)`.
|
903
|
+
|
904
|
+
Returns
|
905
|
+
-------
|
906
|
+
pd.DataFrame
|
907
|
+
* MultiIndex columns (symbol, field) when `len(fields) > 1`
|
908
|
+
* Single-level columns (symbol) when one field & keep_single_level=True
|
873
909
|
"""
|
910
|
+
# ------------------------------------------------------------------ sanity
|
911
|
+
if fields is None:
|
912
|
+
fields = ["close"]
|
874
913
|
if isinstance(symbol_list, str):
|
875
914
|
symbol_list = [symbol_list]
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
915
|
+
|
916
|
+
fields = [f.lower() for f in fields]
|
917
|
+
bad = [f for f in fields if f not in ALLOWED_FIELDS]
|
918
|
+
if bad:
|
919
|
+
raise ValueError(f"Invalid field(s): {bad}. Allowed: {sorted(ALLOWED_FIELDS)}")
|
920
|
+
|
921
|
+
# --------------------------------------------------------------- download
|
922
|
+
DATASETS = [
|
923
|
+
("Stocks-Daily-Price", extend),
|
924
|
+
("ETFs-Daily-Price", extend),
|
925
|
+
("Cryptocurrencies-Daily-Price", extend),
|
926
|
+
("Bonds-Daily-Price", extend),
|
927
|
+
("Commodities-Daily-Price", extend),
|
928
|
+
("Indices-Daily-Price", False), # indices generally have no proxy data
|
929
|
+
]
|
930
|
+
remaining = set(symbol_list) # symbols still to fetch
|
931
|
+
frames = []
|
932
|
+
for dataset_name, ext_flag in DATASETS:
|
933
|
+
if not remaining: # all symbols resolved → stop early
|
934
|
+
break
|
935
|
+
df_part = load_dataset(dataset_name, list(remaining), extend=ext_flag)
|
936
|
+
if not df_part.empty:
|
937
|
+
frames.append(df_part)
|
938
|
+
remaining -= set(df_part["symbol"].unique())
|
939
|
+
df = pd.concat(frames, ignore_index=True)
|
940
|
+
|
889
941
|
df["date"] = pd.to_datetime(df["date"])
|
890
942
|
df.set_index("date", inplace=True)
|
891
943
|
df.sort_index(inplace=True)
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
)
|
896
|
-
|
897
|
-
|
944
|
+
df = df.loc[start_date:end_date]
|
945
|
+
|
946
|
+
# ------------------------------------------------------------- reshape
|
947
|
+
# Pivot can accept a list of values: returns columns = (field, symbol)
|
948
|
+
prices = df.pivot_table(values=fields, index=df.index, columns="symbol")
|
949
|
+
|
950
|
+
# Make outer level = symbol, inner = field → pivot_df[sym] gives OHLC block
|
951
|
+
prices = prices.swaplevel(axis=1).sort_index(axis=1)
|
952
|
+
|
953
|
+
# Optional: flatten back to the legacy layout if only one field requested
|
954
|
+
if keep_single_level and len(fields) == 1:
|
955
|
+
field = fields[0]
|
956
|
+
prices.columns = prices.columns.droplevel(1) # keep only the symbol names
|
957
|
+
# optional: rename index level for clarity
|
958
|
+
prices.name = field
|
959
|
+
|
960
|
+
return prices
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|