backtrader.bokeh.analyzers.recorder 源代码
#!/usr/bin/env python
"""
Data recording analyzer.
Records data during strategy execution for subsequent plotting or analysis.
"""
from collections import OrderedDict
import backtrader as bt
[文档]
class RecorderAnalyzer(bt.Analyzer):
"""
Data recording analyzer.
Records OHLCV data and indicator data during strategy execution.
Args:
indicators: Whether to record indicator data
observers: Whether to record observer data
Example:
cerebro.addanalyzer(RecorderAnalyzer, indicators=True)
# Get data after running
result = cerebro.run()
recorder = result[0].analyzers.recorderanalyzer
data = recorder.get_analysis()
"""
params = (
("indicators", True), # Whether to record indicators
("observers", False), # Whether to record observers
)
[文档]
def __init__(self):
"""Initialize recorder analyzer.
Sets up storage for data sources, indicators, and observers based
on parameter configuration.
"""
super().__init__()
# Data storage
self._data = OrderedDict()
# Initialize data source storage
for i, data in enumerate(self.strategy.datas):
name = getattr(data, "_name", None) or f"data{i}"
self._data[name] = {
"datetime": [],
"open": [],
"high": [],
"low": [],
"close": [],
"volume": [],
}
# Initialize indicator storage
if self.p.indicators:
self._indicators = OrderedDict()
# Initialize observer storage
if self.p.observers:
self._observers = OrderedDict()
[文档]
def start(self):
"""Analyzer start."""
pass
[文档]
def next(self):
"""Record data for each bar."""
# Record data sources
for i, data in enumerate(self.strategy.datas):
name = getattr(data, "_name", f"data{i}")
if name in self._data:
try:
self._data[name]["datetime"].append(data.datetime.datetime(0))
self._data[name]["open"].append(data.open[0])
self._data[name]["high"].append(data.high[0])
self._data[name]["low"].append(data.low[0])
self._data[name]["close"].append(data.close[0])
self._data[name]["volume"].append(
data.volume[0] if hasattr(data, "volume") else 0
)
except Exception:
pass
# Record indicators
if self.p.indicators and hasattr(self.strategy, "_lineiterators"):
indicators = self.strategy._lineiterators.get(1, []) # IndType = 1
for ind in indicators:
ind_name = ind.__class__.__name__
if ind_name not in self._indicators:
self._indicators[ind_name] = OrderedDict()
# Initialize line storage
for line_name in ind.lines._getlinealiases():
self._indicators[ind_name][line_name] = []
# Record value for each line
for line_name in ind.lines._getlinealiases():
try:
line = getattr(ind.lines, line_name)
value = line[0] if len(line) > 0 else None
self._indicators[ind_name][line_name].append(value)
except Exception:
self._indicators[ind_name][line_name].append(None)
# Record observers
if self.p.observers and hasattr(self.strategy, "_lineiterators"):
observers = self.strategy._lineiterators.get(2, []) # ObsType = 2
for obs in observers:
obs_name = obs.__class__.__name__
if obs_name not in self._observers:
self._observers[obs_name] = OrderedDict()
for line_name in obs.lines._getlinealiases():
self._observers[obs_name][line_name] = []
for line_name in obs.lines._getlinealiases():
try:
line = getattr(obs.lines, line_name)
value = line[0] if len(line) > 0 else None
self._observers[obs_name][line_name].append(value)
except Exception:
self._observers[obs_name][line_name].append(None)
[文档]
def stop(self):
"""Analyzer stop."""
pass
[文档]
def get_analysis(self):
"""Return recorded data.
Returns:
OrderedDict: Dictionary containing data, indicators and observers
"""
result = OrderedDict()
result["data"] = self._data
if self.p.indicators:
result["indicators"] = getattr(self, "_indicators", OrderedDict())
if self.p.observers:
result["observers"] = getattr(self, "_observers", OrderedDict())
return result
[文档]
def get_dataframe(self, data_name=None):
"""Convert data to pandas DataFrame.
Args:
data_name: Data source name, None means first data source
Returns:
pandas.DataFrame or None
"""
try:
import pandas as pd
except ImportError:
return None
if data_name is None:
data_name = list(self._data.keys())[0] if self._data else None
if data_name is None or data_name not in self._data:
return None
df = pd.DataFrame(self._data[data_name])
if "datetime" in df.columns:
df.set_index("datetime", inplace=True)
return df