多くの人々は、戦略的な使用のためにローカルデータベースからバックトレーダーにデータを送信することを望んで、独自のローカルマーケットデータベースを確立しています。一般的な方法は、データベースの市場データをパンダのデータフレームに読み込み、このデータフレームのデータをバックトレーダーのパンダのフィードデータオブジェクトに渡して、戦略を使用できるようにすることです。
ただし、一部の学生はパンダのデータフレームを介して転送することを望まず、データベースからバックトレーダーのデータフィードオブジェクトにデータを直接フィードしたいため、データベース用の特別なデータフィードクラスを開発する必要があります。
前回の記事では、MySQLデータベースのデータフィードを開発する方法を紹介しました。この記事では、sqliteデータベースのデータフィードの開発を紹介します。
以下は、sqliteデータベースからデータを読み取るためにバックトレーダーコミュニティによって提供されるフィードクラスSQLiteDataです。試してみることができます。
import datetime as dt
from backtrader import TimeFrame
from backtrader.feed import DataBase
from backtrader import date2num
class SQLiteData(DataBase):
'''
Fetches data from SQLite, and wraps it into a Feed consumable by cerebro
takes url connection string in form of :
sqlite://{database}
this implementation assumes a single table (historical_data) with all prices,
conforming to a schema similar to the following:
symbol TEXT,
date TEXT (YYYY-mm-dd HH:mm),
open REAL,
high REAL,
low REAL,
close REAL,
volume INTEGER,
unique (symbol, date)
if your databases are set up differently, you can override the
start() method.
'''
params = (
('database', None),
('symbol', 'XBTUSD'),
('tick_value', 0.01),
('timeframe ', TimeFrame.Minutes),
('compression', 1),
('fromdate', dt.datetime(1900, 1, 1)),
('todate', dt.datetime.max),
# parameterized column indices for ease of overwriting/re-implementing
('datetime', 0),
('open', 1),
('high', 2),
('low', 3),
('close', 4),
('volume', 5),
('openinterest', -1),
)
def __init__(self):
self._timeframe = self.p.timeframe
self._compression = self.p.compression
self._dataname = '{0}-{1:.2f}'.format(self.p.symbol, self.p.tick_value)
def start(self):
super(SQLiteData, self).start()
self.biter = None
self.preloaded = False
def _preload(self):
engine = self._connect_db()
sql_query = "SELECT `date`,`open`,`high`,`low`,`close`,`volume` FROM `historical_data` WHERE `symbol` = '" + self.p.symbol + "' AND `date` between '" + self.p.fromdate.strftime(
"%Y-%m-%d %H:%M:%S") + "' and '" + self.p.todate.strftime("%Y-%m-%d %H:%M:%S") + "' ORDER BY `date` ASC"
result = engine.execute(sql_query)
dbars = result.fetchall()
result.close()
self.biter = iter(dbars)
def preload(self):
if not self.biter:
self._preload()
while self.load():
pass
self._last()
self.home()
self.biter = None
self.preloaded = True
def _load(self):
if self.preloaded:
return False
if not self.biter:
self._preload()
try:
bar = next(self.biter)
except StopIteration:
return False
for field in self.getlinealiases():
if field == 'datetime':
self.lines.datetime[0] = date2num(dt.datetime.strptime(bar[self.p.datetime], '%Y-%m-%d %H:%M:%S'))
elif field == 'volume':
self.lines.volume[0] = bar[self.p.volume]
else:
# get the column index
colidx = getattr(self.params, field)
if colidx < 0:
# column not present -- skip
continue
# get the line to be set
line = getattr(self.lines, field)
line[0] = float(bar[colidx])
return True
def _connect_db(self):
from sqlalchemy import create_engine
url = 'sqlite:///{0}'.format(self.p.database)
engine = create_engine(url, echo=False)
return engine
3時間前に投稿