ivolatility-backtesting 1.34__tar.gz → 1.35__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.
- {ivolatility_backtesting-1.34 → ivolatility_backtesting-1.35}/PKG-INFO +1 -1
- {ivolatility_backtesting-1.34 → ivolatility_backtesting-1.35}/ivolatility_backtesting/ivolatility_backtesting.py +85 -19
- {ivolatility_backtesting-1.34 → ivolatility_backtesting-1.35}/ivolatility_backtesting.egg-info/PKG-INFO +1 -1
- {ivolatility_backtesting-1.34 → ivolatility_backtesting-1.35}/pyproject.toml +1 -1
- {ivolatility_backtesting-1.34 → ivolatility_backtesting-1.35}/LICENSE +0 -0
- {ivolatility_backtesting-1.34 → ivolatility_backtesting-1.35}/README.md +0 -0
- {ivolatility_backtesting-1.34 → ivolatility_backtesting-1.35}/ivolatility_backtesting/__init__.py +0 -0
- {ivolatility_backtesting-1.34 → ivolatility_backtesting-1.35}/ivolatility_backtesting.egg-info/SOURCES.txt +0 -0
- {ivolatility_backtesting-1.34 → ivolatility_backtesting-1.35}/ivolatility_backtesting.egg-info/dependency_links.txt +0 -0
- {ivolatility_backtesting-1.34 → ivolatility_backtesting-1.35}/ivolatility_backtesting.egg-info/requires.txt +0 -0
- {ivolatility_backtesting-1.34 → ivolatility_backtesting-1.35}/ivolatility_backtesting.egg-info/top_level.txt +0 -0
- {ivolatility_backtesting-1.34 → ivolatility_backtesting-1.35}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ivolatility_backtesting
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.35
|
|
4
4
|
Summary: A universal backtesting framework for financial strategies using the IVolatility API.
|
|
5
5
|
Author-email: IVolatility <support@ivolatility.com>
|
|
6
6
|
Project-URL: Homepage, https://ivolatility.com
|
|
@@ -3656,10 +3656,10 @@ def _api_call_internal(endpoint, cache_config, debug, debug_level, **kwargs):
|
|
|
3656
3656
|
elif debug or cache_config.get('debug', False):
|
|
3657
3657
|
print(f"[CACHE] ✓ Cache hit: {endpoint} ({len(cached_data) if hasattr(cached_data, '__len__') else '?'} records)")
|
|
3658
3658
|
|
|
3659
|
-
# ✅
|
|
3660
|
-
#
|
|
3659
|
+
# ✅ CONSISTENT: Always return list format for backward compatibility
|
|
3660
|
+
# This ensures `if not response.get('data')` works correctly in all strategies
|
|
3661
3661
|
if isinstance(cached_data, pd.DataFrame):
|
|
3662
|
-
return {'data': cached_data, 'status': 'success'
|
|
3662
|
+
return {'data': cached_data.to_dict('records'), 'status': 'success'}
|
|
3663
3663
|
return cached_data
|
|
3664
3664
|
|
|
3665
3665
|
if debug_level >= 3:
|
|
@@ -3773,6 +3773,84 @@ def _api_call_internal(endpoint, cache_config, debug, debug_level, **kwargs):
|
|
|
3773
3773
|
return None
|
|
3774
3774
|
|
|
3775
3775
|
|
|
3776
|
+
# ============================================================
|
|
3777
|
+
# API RESPONSE HELPERS
|
|
3778
|
+
# ============================================================
|
|
3779
|
+
def get_api_data(response, as_dataframe=True):
|
|
3780
|
+
"""
|
|
3781
|
+
Universal helper to extract data from api_call response.
|
|
3782
|
+
Works with both list and DataFrame formats from cache.
|
|
3783
|
+
|
|
3784
|
+
Args:
|
|
3785
|
+
response: Response dict from api_call()
|
|
3786
|
+
as_dataframe: If True (default), always return DataFrame.
|
|
3787
|
+
If False, return list of dicts.
|
|
3788
|
+
|
|
3789
|
+
Returns:
|
|
3790
|
+
DataFrame/list or None if no valid data
|
|
3791
|
+
|
|
3792
|
+
Example:
|
|
3793
|
+
# Get stock data as DataFrame
|
|
3794
|
+
stock_df = get_api_data(api_call('/equities/eod/stock-prices', ...))
|
|
3795
|
+
if stock_df is None:
|
|
3796
|
+
print("No data!")
|
|
3797
|
+
|
|
3798
|
+
# Get as list of dicts
|
|
3799
|
+
records = get_api_data(response, as_dataframe=False)
|
|
3800
|
+
"""
|
|
3801
|
+
if response is None:
|
|
3802
|
+
return None
|
|
3803
|
+
|
|
3804
|
+
data = response.get('data')
|
|
3805
|
+
if data is None:
|
|
3806
|
+
return None
|
|
3807
|
+
|
|
3808
|
+
# Handle DataFrame (from cache)
|
|
3809
|
+
if isinstance(data, pd.DataFrame):
|
|
3810
|
+
if data.empty:
|
|
3811
|
+
return None
|
|
3812
|
+
return data if as_dataframe else data.to_dict('records')
|
|
3813
|
+
|
|
3814
|
+
# Handle list (from API)
|
|
3815
|
+
if not data: # empty list
|
|
3816
|
+
return None
|
|
3817
|
+
|
|
3818
|
+
return pd.DataFrame(data) if as_dataframe else data
|
|
3819
|
+
|
|
3820
|
+
|
|
3821
|
+
def is_api_response_valid(response):
|
|
3822
|
+
"""
|
|
3823
|
+
Check if api_call response contains valid non-empty data.
|
|
3824
|
+
Works with both list and DataFrame formats.
|
|
3825
|
+
|
|
3826
|
+
Args:
|
|
3827
|
+
response: Response dict from api_call()
|
|
3828
|
+
|
|
3829
|
+
Returns:
|
|
3830
|
+
bool: True if response contains valid non-empty data
|
|
3831
|
+
|
|
3832
|
+
Example:
|
|
3833
|
+
response = api_call('/equities/eod/stock-prices', ...)
|
|
3834
|
+
if not is_api_response_valid(response):
|
|
3835
|
+
print("No data available!")
|
|
3836
|
+
return
|
|
3837
|
+
|
|
3838
|
+
# Safe to use response['data'] now
|
|
3839
|
+
df = pd.DataFrame(response['data'])
|
|
3840
|
+
"""
|
|
3841
|
+
if response is None:
|
|
3842
|
+
return False
|
|
3843
|
+
|
|
3844
|
+
data = response.get('data')
|
|
3845
|
+
if data is None:
|
|
3846
|
+
return False
|
|
3847
|
+
|
|
3848
|
+
if isinstance(data, pd.DataFrame):
|
|
3849
|
+
return not data.empty
|
|
3850
|
+
|
|
3851
|
+
return bool(data)
|
|
3852
|
+
|
|
3853
|
+
|
|
3776
3854
|
# ============================================================
|
|
3777
3855
|
# OPTIONS DATA HELPERS
|
|
3778
3856
|
# ============================================================
|
|
@@ -8918,11 +8996,7 @@ def preload_data_universal(config, data_requests=None, debug=False):
|
|
|
8918
8996
|
|
|
8919
8997
|
response = api_call(endpoint, cache_config, debug=debuginfo, **params)
|
|
8920
8998
|
if response and 'data' in response:
|
|
8921
|
-
|
|
8922
|
-
if response.get('_is_dataframe'):
|
|
8923
|
-
df = response['data']
|
|
8924
|
-
else:
|
|
8925
|
-
df = pd.DataFrame(response['data'])
|
|
8999
|
+
df = pd.DataFrame(response['data'])
|
|
8926
9000
|
if len(df) > 0:
|
|
8927
9001
|
all_data.append(df)
|
|
8928
9002
|
|
|
@@ -8983,11 +9057,7 @@ def preload_data_universal(config, data_requests=None, debug=False):
|
|
|
8983
9057
|
|
|
8984
9058
|
response = api_call(endpoint, cache_config, debug=debuginfo, **params)
|
|
8985
9059
|
if response and 'data' in response:
|
|
8986
|
-
|
|
8987
|
-
if response.get('_is_dataframe'):
|
|
8988
|
-
df = response['data'] # Already a DataFrame!
|
|
8989
|
-
else:
|
|
8990
|
-
df = pd.DataFrame(response['data'])
|
|
9060
|
+
df = pd.DataFrame(response['data'])
|
|
8991
9061
|
if len(df) > 0:
|
|
8992
9062
|
# Add cp type if not in response
|
|
8993
9063
|
if cp_type and 'type' not in df.columns and 'optionType' not in df.columns:
|
|
@@ -9009,11 +9079,7 @@ def preload_data_universal(config, data_requests=None, debug=False):
|
|
|
9009
9079
|
params = base_params.copy()
|
|
9010
9080
|
response = api_call(endpoint, cache_config, debug=debuginfo, **params)
|
|
9011
9081
|
if response and 'data' in response:
|
|
9012
|
-
|
|
9013
|
-
if response.get('_is_dataframe'):
|
|
9014
|
-
df = response['data']
|
|
9015
|
-
else:
|
|
9016
|
-
df = pd.DataFrame(response['data'])
|
|
9082
|
+
df = pd.DataFrame(response['data'])
|
|
9017
9083
|
if len(df) > 0:
|
|
9018
9084
|
all_data.append(df)
|
|
9019
9085
|
|
|
@@ -11217,7 +11283,7 @@ class UniversalCacheManager:
|
|
|
11217
11283
|
__all__ = [
|
|
11218
11284
|
'BacktestResults', 'BacktestAnalyzer', 'ResultsReporter',
|
|
11219
11285
|
'ChartGenerator', 'ResultsExporter', 'run_backtest', 'run_backtest_with_stoploss',
|
|
11220
|
-
'init_api', 'api_call', 'APIHelper', 'APIManager',
|
|
11286
|
+
'init_api', 'api_call', 'get_api_data', 'is_api_response_valid', 'APIHelper', 'APIManager',
|
|
11221
11287
|
'ResourceMonitor', 'create_progress_bar', 'update_progress', 'format_time',
|
|
11222
11288
|
'StopLossManager', 'PositionManager', 'StopLossConfig',
|
|
11223
11289
|
'calculate_stoploss_metrics', 'print_stoploss_section', 'create_stoploss_charts',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ivolatility_backtesting
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.35
|
|
4
4
|
Summary: A universal backtesting framework for financial strategies using the IVolatility API.
|
|
5
5
|
Author-email: IVolatility <support@ivolatility.com>
|
|
6
6
|
Project-URL: Homepage, https://ivolatility.com
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ivolatility_backtesting"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.35"
|
|
8
8
|
description = "A universal backtesting framework for financial strategies using the IVolatility API."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [
|
|
File without changes
|
|
File without changes
|
{ivolatility_backtesting-1.34 → ivolatility_backtesting-1.35}/ivolatility_backtesting/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|