# CSV 数据源开发

> [`www.backtrader.com/docu/datafeed-develop-csv/`](https://www.backtrader.com/docu/datafeed-develop-csv/)

`backtrader`已经提供了通用 CSV 数据源和一些特定的 CSV 数据源。总结：

+   通用 CSV 数据

+   VisualChartCSV 数据

+   YahooFinanceData（用于在线下载）

+   YahooFinanceCSVData（用于已下载的数据）

+   BacktraderCSVData（内部…用于测试目的，但可用）

但即使如此，最终用户可能希望为特定的 CSV 数据源开发支持。

通常的座右铭可能是：“说起来容易做起来难”。实际上，结构的目的是使其易于操作。

步骤：

+   继承自`backtrader.CSVDataBase`

+   如有必要，定义任何`params`

+   在`start`方法中进行任何初始化

+   在`stop`方法中进行任何清理

+   定义一个`_loadline`方法，在其中进行实际工作

    此方法接收一个参数：linetokens。

    如其名，此数据包含根据`separator`参数（继承自基类）拆分当前行后的标记。

    如果完成工作后有新数据……填充相应行并返回`True`

    如果没有可用内容，因此解析已经结束：返回`False`

    如果在幕后代码中读取文件行时发现没有更多行可解析，则可能甚至不需要返回`False`。

已经考虑到的事项：

+   打开文件（或接收文件样式对象）

+   如果指示存在，则跳过标题行

+   读取行

+   对行进行标记

+   预加载支持（一次性在内存中加载整个数据源）

通常，一个例子胜过千言万语的需求描述。让我们使用`BacktraderCSVData`中定义的内部 CSV 解析代码的简化版本。这个版本不需要初始化或清理（例如，可以是打开套接字，然后稍后关闭）。

注意

`backtrader`数据源包含通常的行业标准数据源，需要填充。即：

+   日期时间

+   打开

+   高

+   低

+   关闭

+   成交量

+   持仓量

如果您的策略/算法或简单的数据查看仅需要例如收盘价，则可以将其他值保持不变（每次迭代结束之前，它们会自动填充为 float（'NaN'）值，以使最终用户代码有机会执行任何操作。

在此示例中，仅支持每日格式：

```py
`import itertools
...
import backtrader as bt

class MyCSVData(bt.CSVDataBase):

    def start(self):
        # Nothing to do for this data feed type
        pass

    def stop(self):
        # Nothing to do for this data feed type
        pass

    def _loadline(self, linetokens):
        i = itertools.count(0)

        dttxt = linetokens[next(i)]
        # Format is YYYY-MM-DD
        y = int(dttxt[0:4])
        m = int(dttxt[5:7])
        d = int(dttxt[8:10])

        dt = datetime.datetime(y, m, d)
        dtnum = date2num(dt)

        self.lines.datetime[0] = dtnum
        self.lines.open[0] = float(linetokens[next(i)])
        self.lines.high[0] = float(linetokens[next(i)])
        self.lines.low[0] = float(linetokens[next(i)])
        self.lines.close[0] = float(linetokens[next(i)])
        self.lines.volume[0] = float(linetokens[next(i)])
        self.lines.openinterest[0] = float(linetokens[next(i)])

        return True` 
```

代码期望所有字段已就位并可转换为浮点数，除日期时间外，日期时间具有固定的 YYYY-MM-DD 格式，并且可在不使用`datetime.datetime.strptime`的情况下解析。

只需添加几行代码，即可满足更复杂的需求，以处理空值，日期格式解析。`GenericCSVData`执行此操作。

## 购买者注意

使用`GenericCSVData`现有数据源和继承，可以完成很多工作以支持各种格式。

让我们为[Sierra Chart](https://www.sierrachart.com)每日格式添加支持（始终以 CSV 格式存储）。

定义（通过查看一个**‘.dly’**数据文件：

+   **字段**：日期、开盘价、最高价、最低价、收盘价、成交量、持仓量

    行业标准和已经由`GenericCSVData`支持的标准顺序（也是行业标准）

+   **分隔符**：，

+   **日期格式**：YYYY/MM/DD

针对这些文件的解析器：

```py
`class SierraChartCSVData(backtrader.feeds.GenericCSVData):

    params = (('dtformat', '%Y/%m/%d'),)` 
```

`params`的定义只是重新定义基类中的一个现有参数。在这种情况下，只需更改日期的格式化字符串。

Et voilá … **Sierra Chart** 的解析器完成了。

下面是`GenericCSVData`的参数定义，以便提醒：

```py
`class GenericCSVData(feed.CSVDataBase):
    params = (
        ('nullvalue', float('NaN')),
        ('dtformat', '%Y-%m-%d %H:%M:%S'),
        ('tmformat', '%H:%M:%S'),

        ('datetime', 0),
        ('time', -1),
        ('open', 1),
        ('high', 2),
        ('low', 3),
        ('close', 4),
        ('volume', 5),
        ('openinterest', 6),
    )` 
```
