Source code for backtrader.feeds.vchartfile

#!/usr/bin/env python
"""VChartFile Data Feed Module - VisualChart file interface.

This module provides the VChartFile feed for reading VisualChart
binary on-disk files using market codes.

Classes:
    VChartFile: VisualChart binary file feed by market code.

Example:
    >>> data = bt.feeds.VChartFile(dataname='015ES')
    >>> cerebro.adddata(data)
"""

import os.path
from datetime import datetime
from struct import unpack

from .. import stores
from ..dataseries import TimeFrame
from ..feed import DataBase
from ..utils import date2num  # avoid dict lookups
from ..utils.log_message import get_logger

logger = get_logger(__name__)


[docs] class VChartFile(DataBase): """ Support for `Visual Chart <www.visualchart.com>`_ binary on-disk files for both daily and intradaily formats. Note: - ``dataname``: Market code displayed by Visual Chart. Example: 015ES for EuroStoxx 50 continuous future """ def __init__(self, **kwargs): """Initialize the VChartFile data feed. Args: **kwargs: Keyword arguments for data feed configuration. """ super().__init__(**kwargs) # Handle original metaclass registration functionality if hasattr(stores, "VChartFile"): stores.VChartFile.DataCls = self.__class__ self.f = None self._barfmt = None self._dtsize = None self._barsize = None self._store = None
[docs] def start(self): """Start the VChartFile data feed. Opens the VisualChart binary file for reading. """ super().start() if self._store is None: self._store = stores.VChartFile() self._store.start() self._store.start(data=self) # Choose extension and extraction/calculation parameters if self.p.timeframe < TimeFrame.Minutes: ext = ".tck" # seconds will still need resampling # FIXME: find reference to tick counter for format elif self.p.timeframe < TimeFrame.Days: ext = ".min" self._dtsize = 2 self._barsize = 32 self._barfmt = "IIffffII" else: ext = ".fd" self._barsize = 28 self._dtsize = 1 self._barfmt = "IffffII" # Construct a full path basepath = self._store.get_datapath() # Example: 01 + 0 + 015ES + .fd -> 010015ES.fd dataname = "01" + "0" + self.p.dataname + ext # 015ES -> 0 + 015 -> 0015 mktcode = "0" + self.p.dataname[0:3] # basepath/0015/010015ES.fd path = os.path.join(basepath, mktcode, dataname) try: self.f = open(path, "rb") except OSError: self.f = None
[docs] def stop(self): """Stop the VChartFile data feed. Closes the open file handle. """ if self.f is not None: self.f.close() self.f = None
def _load(self): if self.f is None: return False # cannot load more try: bardata = self.f.read(self._barsize) except OSError: self.f = None # cannot return, nullify file return False # cannot load more if not bardata or len(bardata) < self._barsize: self.f = None # cannot return, nullify file return False # cannot load more try: bdata = unpack(self._barfmt, bardata) except Exception as e: logger.warning("vchart bar unpack failed, stopping feed: %s", e) self.f = None return False # First Date y, md = divmod(bdata[0], 500) # Years stored as if they had 500 days m, d = divmod(md, 32) # Months stored as if they had 32 days dt = datetime(y, m, d) # Time if self._dtsize > 1: # Minute Bars # Daily Time is stored in seconds hhmm, ss = divmod(bdata[1], 60) hh, mm = divmod(hhmm, 60) dt = dt.replace(hour=hh, minute=mm, second=ss) else: # Daily Bars dt = datetime.combine(dt, self.p.sessionend) self.lines.datetime[0] = date2num(dt) # Store time # Get the rest of the fields o, h, low, c, v, oi = bdata[self._dtsize :] self.lines.open[0] = o self.lines.high[0] = h self.lines.low[0] = low self.lines.close[0] = c self.lines.volume[0] = v self.lines.openinterest[0] = oi return True # a bar has been successfully loaded