循环遍历多个csv文件并计算NYSE tick的最有效方法

时间:2013-10-05 15:58:59

标签: python

我在具有以下结构的单独csv文件中拥有所有纽约证券交易所股票的1分钟数据:

(数据,开放,高,低,收盘,成交量)

2013-09-16 09:30:00,461.01,461.49,461,461,183507
2013-09-16 09:31:00,460.82,461.6099,460.39,461.07,212774
...
2013-09-16 15:59:00,449.72,450.0774,449.59,449.95,146399
2013-09-16 16:00:00,450.12,450.12,449.65,449.65,444594
2013-09-17 09:30:00,448,448,447.5,447.96,173624
2013-09-17 09:31:00,449.2628,449.68,447.5,448,193186
....

我想计算一下纽约证券交易所tick (上涨交易的股票数量减去下跌交易的股票数量)并将其写入新的csv文件中结构:

2013-09-16 09:30:00,[tick]
2013-09-16 09:31:00,[tick]
...
2013-09-16 15:59:00,[tick]
2013-09-16 16:00:00,[tick]
2013-09-17 09:30:00,[tick]
2013-09-17 09:31:00,[tick]
....

基本上,我需要:

Loop every csv file
    # For every file compare close[t] to close[t-1]
    If close[t] > close[t-1]:
        increment tick by 1
    Else:
        subtract 1 from tick 

你如何在python中最有效地做到这一点?

2 个答案:

答案 0 :(得分:3)

我可能会使用pandas库。它具有很多很好的功能,特别适用于时间序列和OHLC数据,但我们不会在这里使用任何一个。

import glob
import numpy as np
import pandas as pd

stocks = glob.glob("stock*.csv")

total_tick = 0
for stock in stocks:
    df = pd.read_csv(stock, 
                     names=["time", "open", "high", "low", "close", "volume"],
                     parse_dates=[0], index_col="time")
    tick = df["close"].diff().apply(np.sign).fillna(0.0)
    total_tick += tick

total_tick.to_csv("tick.csv")

产生类似

的输出
2013-09-16 09:30:00,0.0
2013-09-16 09:31:00,3.0
2013-09-16 15:59:00,-5.0
2013-09-16 16:00:00,-3.0
2013-09-17 09:30:00,1.0
2013-09-17 09:31:00,-1.0

我已经制作了与您相似的样本数据。


基本思想是你可以将csv文件读入一个名为DataFrame的对象中:

>>> df
                         open      high     low       close  volume
time                                                               
2013-09-16 09:30:00  461.0100  461.4900  461.00  453.484089  183507
2013-09-16 09:31:00  460.8200  461.6099  460.39  474.727508  212774
2013-09-16 15:59:00  449.7200  450.0774  449.59  436.010403  146399
2013-09-16 16:00:00  450.1200  450.1200  449.65  455.296584  444594
2013-09-17 09:30:00  448.0000  448.0000  447.50  447.465545  173624
2013-09-17 09:31:00  449.2628  449.6800  447.50  477.785506  193186

我们可以选择一列:

>>> df["close"]
time
2013-09-16 09:30:00    453.484089
2013-09-16 09:31:00    474.727508
2013-09-16 15:59:00    436.010403
2013-09-16 16:00:00    455.296584
2013-09-17 09:30:00    447.465545
2013-09-17 09:31:00    477.785506
Name: close, dtype: float64

区别对待,注意如果我们从前一个值中减去,那么初始值是未定义的:

>>> df["close"].diff()
time
2013-09-16 09:30:00          NaN
2013-09-16 09:31:00    21.243419
2013-09-16 15:59:00   -38.717105
2013-09-16 16:00:00    19.286181
2013-09-17 09:30:00    -7.831039
2013-09-17 09:31:00    30.319961
Name: close, dtype: float64

根据其标志,将其设为正面或负面:

>>> df["close"].diff().apply(np.sign)
time
2013-09-16 09:30:00   NaN
2013-09-16 09:31:00     1
2013-09-16 15:59:00    -1
2013-09-16 16:00:00     1
2013-09-17 09:30:00    -1
2013-09-17 09:31:00     1
Name: close, dtype: float64

用{0}填充NaN

>>> df["close"].diff().apply(np.sign).fillna(0)
time
2013-09-16 09:30:00    0
2013-09-16 09:31:00    1
2013-09-16 15:59:00   -1
2013-09-16 16:00:00    1
2013-09-17 09:30:00   -1
2013-09-17 09:31:00    1
dtype: float64

这假设记录时间与所有股票匹配:如果没有,则有强大的重采样工具可用于对齐它们。

答案 1 :(得分:1)

这个问题的几个部分在Python中有优雅(但可能不是很明显)的解决方案。

第一个棘手的部分是立即处理打开所有文件。通常你想使用with open(filename),但是当有一个(可能是可变的)大量文件要打开时,这不起作用。相反,您可以使用contextlib.ExitStack上下文管理器来处理文件:

import contextlib
import csv
import itertools

def tick(filenames):
    with contextlib.ExitStack() as stack:
        files = [stack.enter_context(open(name, newline=""))
                 for name in filenames]

下一步是读取读取csv文件的句柄。使用csv模块实际上非常简单:

        CSVs = [csv.reader(file) for file in files]

现在,当我们迭代CSV文件时,我们需要将每一行与前一行一起考虑。也就是说,我们需要同时产生当前和前一行。使用itertools.teezip(在tick之前或之后坚持此功能)有一种优雅的方法:

def current_and_prev(iterable):
    a, b = itertools.tee(iterable, 2)
    next(a) # throw away first value from "current" iterator
    return zip(a, b)

回到tick函数,我们可以围绕每个csv.reader实例进行包装:

        pair_iterators = [current_and_prev(CSV) for CSV in CSVs]

现在,我们希望并行地迭代所有迭代器(因为我们需要检查它们以计算tick)。 zip是执行此操作的工具:

        for pairs in zip(*pair_iterators):

pairs将是一个包含每个文件的csv数据的当前行和前一行的2元组的元组。我们需要从其中一条current行中获取时间戳,然后对它们进行迭代以查找哪些是上升的,哪些是在下降中。

            timestamp = pair[0][0][0] # first file, current line, first column
            tick = 0
            for current, prev in pairs:
                if float(current[-2]) > float(prev[-2]):
                    tick += 1
                elif float(current[-2]) < float(prev[-2]):
                    tick -= 1
            yield timestamp, tick