Skip to content

Commit 89a4f93

Browse files
committed
ENH: Add lib.random_ohlc_data() OHLC data generator
1 parent f1f52da commit 89a4f93

File tree

2 files changed

+42
-1
lines changed

2 files changed

+42
-1
lines changed

β€Žbacktesting/lib.pyβ€Ž

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,39 @@ def wrap_func(resampled, *args, **kwargs):
277277
return array
278278

279279

280+
def random_ohlc_data(example_data: pd.DataFrame, random_state: int = None) -> pd.DataFrame:
281+
"""
282+
OHLC data generator. The generated OHLC data has basic
283+
[descriptive statistics](https://en.wikipedia.org/wiki/Descriptive_statistics)
284+
similar to the provided `example_data`.
285+
286+
Such random data can be effectively used for stress testing trading
287+
strategy robustness, Monte Carlo simulations, significance testing, etc.
288+
289+
>>> from backtesting.test import EURUSD
290+
>>> ohlc_generator = random_ohlc_data(EURUSD)
291+
>>> next(ohlc_generator) # returns new random data
292+
...
293+
>>> next(ohlc_generator) # returns new random data
294+
...
295+
"""
296+
def shuffle(x):
297+
return x.sample(frac=1, random_state=random_state)
298+
299+
if len(example_data.columns & {'Open', 'High', 'Low', 'Close'}) != 4:
300+
raise ValueError("`data` must be a pandas.DataFrame with columns "
301+
"'Open', 'High', 'Low', 'Close'")
302+
while True:
303+
df = shuffle(example_data)
304+
df.index = example_data.index
305+
padding = df.Close - df.Open.shift(-1)
306+
gaps = shuffle(example_data.Open.shift(-1) - example_data.Close)
307+
deltas = (padding + gaps).shift(1).fillna(0).cumsum()
308+
for key in ('Open', 'High', 'Low', 'Close'):
309+
df[key] += deltas
310+
yield df
311+
312+
280313
class SignalStrategy(Strategy):
281314
"""
282315
A simple helper strategy that operates on position entry/exit signals.

β€Žbacktesting/test/_test.pyβ€Ž

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
SignalStrategy,
2525
TrailingStrategy,
2626
resample_apply,
27-
plot_heatmaps
27+
plot_heatmaps,
28+
random_ohlc_data,
2829
)
2930
from backtesting.test import GOOG, EURUSD, SMA
3031
from backtesting._util import _Indicator, _as_str, _Array, try_
@@ -726,6 +727,13 @@ def test_plot_heatmaps(self):
726727
plot_heatmaps(heatmap, filename=f)
727728
time.sleep(5)
728729

730+
def test_random_ohlc_data(self):
731+
generator = random_ohlc_data(GOOG)
732+
new_data = next(generator)
733+
self.assertEqual(list(new_data.index), list(GOOG.index))
734+
self.assertEqual(new_data.shape, GOOG.shape)
735+
self.assertEqual(list(new_data.columns), list(GOOG.columns))
736+
729737
def test_SignalStrategy(self):
730738
class S(SignalStrategy):
731739
def init(self):

0 commit comments

Comments
Β (0)