@@ -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+
280313class SignalStrategy (Strategy ):
281314 """
282315 A simple helper strategy that operates on position entry/exit signals.
0 commit comments