导航属性没有被赋值_backtrader代码第八步 —— YahooFinanceCSVData属性方法解读

阅读建议:

该篇文章主要解读YahooFinanceCSVData类中的属性方法

从内容上看,本章与第五、六、七篇属于同一系列,应该合起来阅读

就本章而言,建议从后往前阅读,本章分为10个类,按第10、9...、1的顺序的类来看。

类图先上:

260ef1bfeb36c2d9b82856ed53ab2254.png

代码解读:

1、

YahooFinanceCSVData

class YahooFinanceCSVData(feed.CSVDataBase):
    lines = ('adjclose',)
​
    params = (
        ('reverse', False),
        ('adjclose', True),
        ('adjvolume', True),
        ('round', True),
        ('decimals', 2),
        ('roundvolume', False),
        ('swapcloses', False),
    )
    
    def start(self):
    
    def _loadline(self, linetokens):

解读:

  1. 在MetaLineSeries元类的__new__方法中,YahooFinanceCSVData及其父类中的lines属性会被转化为Lines类
  2. 在MetaLineRoot元类的__donew__方法中,YahooFinanceCSVData类在生成对象的过程中,类属性params会赋值给对象属性,同时,赋值给对象属性self.p
  3. start函数分别在父类CSVDataBase和祖先类AbstractDataBase中有定义,在祖先类AbstractDataBase中设置队列容器及初始化状态0,在父类CSVDataBase中打开文件self.p.dataname并赋值给self.f,在类YahooFinanceCSVData中读取self.f的内容放入内存数据并重新赋值给self.f

2、

CSVDataBase

class CSVDataBase(with_metaclass(MetaCSVDataBase, DataBase)):
    f = None
    params = (('headers', True), ('separator', ','),)
    
    def start(self):
    
    def stop(self):
    
    def preload(self):
    
    def _load(self):
    
    def _getnextline(self):
    

解读:

  1. 设计:该类用于处理csv数据,包括打开文件,读取数据且格式化。子类只需覆盖_loadline方法即可使用
  2. start方法:打开文件并赋值给self.f, 给分隔符self.separator赋值
  3. _load方法:从文件句柄self.f中读取一行,内容分割后传递给方法_loadline,读取失败返回False
  4. _getnextline方法:从文件句柄self.f中读取一行,内容分割后返回

3、

DataBase

class DataBase(AbstractDataBase):
    pass

4、

AbstractDataBase

class AbstractDataBase(with_metaclass(MetaAbstractDataBase,
                                      dataseries.OHLCDateTime)):
    params = (
        ('dataname', None),
        ('name', ''),
        ('compression', 1),
        ('timeframe', TimeFrame.Days),
        ('fromdate', None),
        ('todate', None),
        ('sessionstart', None),
        ('sessionend', None),
        ('filters', []),
        ('tz', None),
        ('tzinput', None),
        ('qcheck', 0.0),  # timeout in seconds (float) to check for events
        ('calendar', None),
    )
    
    (CONNECTED, DISCONNECTED, CONNBROKEN, DELAYED,
     LIVE, NOTSUBSCRIBED, NOTSUPPORTED_TF, UNKNOWN) = range(8)
​
    _NOTIFNAMES = [
        'CONNECTED', 'DISCONNECTED', 'CONNBROKEN', 'DELAYED',
        'LIVE', 'NOTSUBSCRIBED', 'NOTSUPPORTED_TIMEFRAME', 'UNKNOWN']
        
    @classmethod
    def _getstatusname(cls, status):
        return cls._NOTIFNAMES[status]
        
    _compensate = None
    _feed = None
    _store = None
​
    _clone = False
    _qcheck = 0.0
​
    _tmoffset = datetime.timedelta()
​
    # Set to non 0 if resampling/replaying
    resampling = 0
    replaying = 0
    
    _started = False
    
    def _start_finish(self):
    
    def _start(self):
    
    def _timeoffset(self):
    
    def _getnexteos(self):
    
    def _gettzinput(self):
    
    def _gettz(self):
    
    def date2num(self, dt):
    
    def num2date(self, dt=None, tz=None, naive=True):
    
    def haslivedata(self):
    
    def do_qcheck(self, onoff, qlapse):
    
    def islive(self):
    
    def put_notification(self, status, *args, **kwargs):
    
    def get_notifications(self):
    
    def getfeed(self):
    
    def qbuffer(self, savemem=0, replaying=False):
    
    def start(self):
    
    def stop(self):
    
    def clone(self, **kwargs):
    
    def copyas(self, _dataname, **kwargs):
    
    def setenvironment(self, env):
    
    def getenvironment(self):
    
    def addfilter_simple(self, f, *args, **kwargs):
    
    def addfilter(self, p, *args, **kwargs):
    
    def compensate(self, other):
    
    def _tick_nullify(self):
    
    def _tick_fill(self, force=False):
    
    def advance_peek(self):
    
    def advance(self, size=1, datamaster=None, ticks=True):
    
    def preload(self):
    
    def _last(self, datamaster=None):
    
    def _check(self, forcedata=None):
    
    def load(self):
    
    def _load(self):
    
    def _add2stack(self, bar, stash=False):
    
    def _save2stack(self, erase=False, force=False, stash=False):
    
    def _updatebar(self, bar, forward=False, ago=0):
    
    def _fromstack(self, forward=False, stash=False):
    
    def resample(self, **kwargs):
    
    def replay(self, **kwargs):
    

解读:

  1. 在类属性params主要提供时间相关的参数,包括date相关,time相关,timezone相关,calendar相关
  2. 方法_start_finish,时间相关变量赋值给对象属性,_tz, _tzinput, fromdate, _sessionstart, _calendar等
  3. 方法_gettzinput和_gettz中的tzparse函数,用于给参数tz赋予替换时区的方法
  4. 方法date2num和num2date用于添加时区来考虑数字和日期的相互转换
  5. 方法put_notification和get_notifications处理通知和状态相关的变量
  6. 方法qbuffer用于给数据线设置qbuffer
  7. 方法addfileter_simple和addfilter负责给属性_filters添加过滤器
  8. 方法compensate用于绑定其他的对象,是信息共通
  9. 方法_tick_nullify用于在K线合成过程中返回None值
  10. 方法_tick_fill将各条线的最新值和第0条数据线的最新值赋值给对象
  11. 方法adcance_peek用于返回下一个时间,如果没有,则返回无穷值
  12. 方法advance用于数据线在不同情况下往前推进size步
  13. 方法next用于返回是否新的bar生成
  14. 方法_last和_check用于过滤器对数据添加干预
  15. 方法load用于循环下载数据,同时进行时间处理和过滤处理
  16. 方法_fromstack从属性_barstack或_barstach中获取数据并赋值给line
  17. 方法_add2stack和_save2stack分别往属性_barstack或_barstach中添加bar
  18. 方法_updatebar用于执行bar来更新数据线
  19. 方法resample和replay用于添加特定的过滤器

5、

OHLCDateTime

class OHLCDateTime(OHLC):
    lines = (('datetime'),)

解读:

  1. 添加类属性lines中的'datetime'

6、

OHLC

class OHLC(DataSeries):
    lines = ('close', 'low', 'high', 'open', 'volume', 'openinterest',)

解读:

  1. 添加类属性lines中的开高低收成交量持仓量

7、

DataSeries

class DataSeries(LineSeries):
    plotinfo = dict(plot=True, plotind=True, plotylimited=True)
​
    _name = ''
    _compression = 1
    _timeframe = TimeFrame.Days
​
    Close, Low, High, Open, Volume, OpenInterest, DateTime = range(7)
​
    LineOrder = [DateTime, Open, High, Low, Close, Volume, OpenInterest]
    
    def getwriterheaders(self):
    
    def getwritervalues(self):
    
    def getwriterinfo(self):

解读:

  1. 该类开始专注数据线中的数值,主要用于查询各条数据线名称及最新值
  2. 定义默认类属性:plotinfo
  3. 数据线顺序LineOrder,数据线的前7条分别为日期,开、高、低、收、成交价、持仓量
  4. getwriteheaders/getwritervalues方法:得到所有数据线名称/最新数据
  5. getwritervalues方法:获取关于name,timeframe和compression相关的有序字典

8、

LineSeries

class LineSeries(with_metaclass(MetaLineSeries, LineMultiple)):
    plotinfo = dict(
        plot=True,
        plotmaster=None,
        legendloc=None,
    )
​
    csv = True
    
    @property
    def array(self):
    
    def __getattr__(self, name):
    
    def __len__(self):
    
    def __getitem__(self, key):
    
    def __setitem__(self, key, value):
    
    def __init__(self, *args, **kwargs):
    
    def plotlabel(self):
    
    def _plotlabel(self):
    
    def _getline(self, line, minusall=False):
    
    def __call__(self, ago=None, line=-1):
    
    def forward(self, value=NAN, size=1):
    
    def backwards(self, size=1, force=False):
    
    def rewind(self, size=1):
    
    def extend(self, value=NAN, size=0):
    
    def reset(self):
    
    def home(self):
    
    def advance(self, size=1):

解读:

  1. lineSeries很重要,从类图上看,它使用了新的元类MetaLineSeries。从功能角度思考,它最终要的是为实例属性self.lines赋予相应的Lines对象
  2. 通过Lines对象,来实现对数据的查询和统计功能
    a. 统计功能:__len__,
    b. 查询功能:__getitem__,forward/backwards/rewind/extend/reset/home/advance c. 改功能:__setitem__

9、

LineMultiple

class LineMultiple(LineRoot):
    def reset(self):
    
    def _stage1(self):
    
    def _stage2(self):
    
    def addminperiod(self, minperiod):
    
    def incminperiod(self, minperiod):
    
    def _makeoperation(self, other, operation, r=False, _ownerskip=None):
    
    def _makeoperationown(self, operation, _ownerskip=None):
    
    def qbuffer(self, savemem=0):
    
    def minbuffer(self, size):

解读:

  1. LineMultiple继承LineRoot,由“一条数据线”变为“多条数据线”,即示例属性self.lines中保存着多条数据线,每条数据线都是一个LineRoot对象。这样,我们就有了两个概念,多条数据线集合的概念和单条数据线的概念。在该类型中,没有往集合中放数据线的方法,相信在子类中会填充相关方法
  2. LineMultiple做了一件事,即对"数据线集合"设置属性(例如_stage和period)的同时,对每条"数据线”设置属性,在方法_stage1/_stage2/addminperiod/incminperiod/qbuffer/minbuffer中实现
  3. 从这个类中,回答在父类LineRoot解读中的遗留问题:_operation_stage1和_operation_stage2区别是什么
    a. 在_opstage=2状态中,默认操作是对self[0]施加operation
    b. 在_opstage=1状态下,可以重写方法_makeoperation和_makeoperationown来调整操作对象,在类LineMultiple中,重写方法,修改操作对象为self.lines[0], 即对集合中的第一条数据线进行操作,后续中加入数据线集合的数据线应该会重写方法_makeoperation和_makeoperationown

10、

LineRoot

class LineRoot(with_metaclass(MetaLineRoot, object)):
    '''
    Defines a common base and interfaces for Single and Multiple
    LineXXX instances
​
        Period management
        Iteration management
        Operation (dual/single operand) Management
        Rich Comparison operator definition
    '''
    _OwnerCls = None
    _minperiod = 1
    _opstage = 1
​
    IndType, StratType, ObsType = range(3)
    
    def _stage1(self):
    
    def _stage2(self):
    
    def _operation(self, other, operation, r=False, intify=False):
    
    def _operationown(self, operation):
    
    def qbuffer(self, savemem=0):
    
    def minbuffer(self, size):
    
    def setminperiod(self, minperiod):
    
    def updateminperiod(self, minperiod):
    
    def addminperiod(self, minperiod):
    
    def incminperiod(self, minperiod):
    
    def prenext(self):
    
    def nextstart(self):
    
    def next(self):
    
    def preonce(self, start, end):
    
    def oncestart(self, start, end):
    
    def once(self, start, end):
    
    def _makeoperation(self, other, operation, r=False, _ownerskip=None):
        raise NotImplementedError
​
    def _makeoperationown(self, operation, _ownerskip=None):
        raise NotImplementedError
​
    def _operationown_stage1(self, operation):
        '''
        Operation with single operand which is "self"
        '''
        return self._makeoperationown(operation, _ownerskip=self)
​
    def _roperation(self, other, operation, intify=False):
        '''
        Relies on self._operation to and passes "r" True to define a
        reverse operation
        '''
        return self._operation(other, operation, r=True, intify=intify)
​
    def _operation_stage1(self, other, operation, r=False, intify=False):
        '''
        Two operands' operation. Scanning of other happens to understand
        if other must be directly an operand or rather a subitem thereof
        '''
        if isinstance(other, LineMultiple):
            other = other.lines[0]
​
        return self._makeoperation(other, operation, r, self)
​
    def _operation_stage2(self, other, operation, r=False):
        '''
        Rich Comparison operators. Scans other and returns either an
        operation with other directly or a subitem from other
        '''
        if isinstance(other, LineRoot):
            other = other[0]
​
        # operation(float, other) ... expecting other to be a float
        if r:
            return operation(other, self[0])
​
        return operation(self[0], other)
​
    def _operationown_stage2(self, operation):
        return operation(self[0])
​
    def __add__(self, other):
        return self._operation(other, operator.__add__)
​
    def __radd__(self, other):
        return self._roperation(other, operator.__add__)
​
    def __sub__(self, other):
        return self._operation(other, operator.__sub__)
​
    def __rsub__(self, other):
        return self._roperation(other, operator.__sub__)
​
    def __mul__(self, other):
        return self._operation(other, operator.__mul__)
​
    def __rmul__(self, other):
        return self._roperation(other, operator.__mul__)
​
    def __div__(self, other):
        return self._operation(other, operator.__div__)
​
    def __rdiv__(self, other):
        return self._roperation(other, operator.__div__)
​
    def __floordiv__(self, other):
        return self._operation(other, operator.__floordiv__)
​
    def __rfloordiv__(self, other):
        return self._roperation(other, operator.__floordiv__)
​
    def __truediv__(self, other):
        return self._operation(other, operator.__truediv__)
​
    def __rtruediv__(self, other):
        return self._roperation(other, operator.__truediv__)
​
    def __pow__(self, other):
        return self._operation(other, operator.__pow__)
​
    def __rpow__(self, other):
        return self._roperation(other, operator.__pow__)
​
    def __abs__(self):
        return self._operationown(operator.__abs__)
​
    def __neg__(self):
        return self._operationown(operator.__neg__)
​
    def __lt__(self, other):
        return self._operation(other, operator.__lt__)
​
    def __gt__(self, other):
        return self._operation(other, operator.__gt__)
​
    def __le__(self, other):
        return self._operation(other, operator.__le__)
​
    def __ge__(self, other):
        return self._operation(other, operator.__ge__)
​
    def __eq__(self, other):
        return self._operation(other, operator.__eq__)
​
    def __ne__(self, other):
        return self._operation(other, operator.__ne__)
​
    def __nonzero__(self):
        return self._operationown(bool)
​
    __bool__ = __nonzero__
​
    # Python 3 forces explicit implementation of hash if
    # the class has redefined __eq__
    __hash__ = object.__hash__

解读:

  1. 这是数据线最原始的父类,所以必须要自己先从时序数据最基础的功能思考—— K线合成和数据运算,可以以tick价格序列为例: a. 价格需要需要合成K线,如何计算每一根Kbar呢?
    Kbar周期:在类变量_minperiod中实现,调整周期在方法setminperiod,updateminperiod中实现
    Kbar开盘价:在方法nextstart/next中实现,本质就是处理一个周期后的第一个价格
    Kbar最高价最低价:在方法prenext中实现,本质就是在一个周期结束前不断比较价格
    Kbar收盘价:在方法prenext中实现,本质就是在一个周期结束前不断更新价格 b. 方法nextstart/next/prenext都是针对时间戳上的价格,那引申到时间段上的价 格,就衍生出了 nextonce/once/preonce方法 c. 关于数据运算,间接通过方法_operation/_operationown来实现
  2. 从LineRoot的元类的__new__方法可知,LineRoot的继承类中的params参数会打包到一块
  3. 这个类的解读会遗留一个问题,即_operation_stage1和_operation_stage2的区别是什么
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值