Python 移动平均交叉回溯测试中的错误

Python 移动平均交叉回溯测试中的错误,python,pandas,Python,Pandas,我试图用熊猫对移动平均线交叉策略进行回溯测试 首先,我定义了一个类(书),其中包括股票数量、现金金额和资产总额 该类中有3个函数,用于在生成买入或卖出信号时计算账簿状态 这是我的代码,但当我测试时,我可能会发现股票和总资产的计算错误 有什么问题吗 import pandas as pd from pandas_datareader import data as pdr # download dataframe test = pdr.get_data_yahoo("SPY", start="20

我试图用熊猫对移动平均线交叉策略进行回溯测试

首先,我定义了一个类(书),其中包括股票数量、现金金额和资产总额

该类中有3个函数,用于在生成买入或卖出信号时计算账簿状态

这是我的代码,但当我测试时,我可能会发现股票和总资产的计算错误

有什么问题吗

import pandas as pd
from pandas_datareader import data as pdr

# download dataframe
test = pdr.get_data_yahoo("SPY", start="2000-01-01")

class Book:
    def __init__(self, stocks = 0, money = 100, asset = 0):
        self.stocks = stocks
        self.money = money
        self.asset = asset

    def buy(self, price):
        if self.money == 0:
            return
        self.stocks += self.money/price
        self.money -= (price * self.stocks)
        self.asset = self.stocks * price + self.money

    def sell(self, price):
        if self.stocks == 0:
            return
        self.money += (price * self.stocks)
        self.stocks = 0
        self.asset = self.stocks * price + self.money

    def assetEvaluate(self,price):
        self.asset = self.stocks * price + self.money

test['ma20'] = test.Close.rolling(20).mean()

def macrossover(df, book):
    result = []
    for i, r in df.iterrows():
        if df.Close[i] > df.ma20[i]:
            book.buy(df.Close[i])
        elif df.Close[i] < df.ma20[i]:
            book.sell(df.Close[i])
        else:                        
            book.assetEvaluate(df.Close[i])
        result.append([i,df.Close[i], book.stocks, book.money, book.asset])

    df = pd.DataFrame(result, columns=['date','close','stocks','money','asset'])
    df.set_index('date', inplace=True)
    print(df)

a = Book()
macrossover(test,a)

我已按如下方式更新了您的代码,现在似乎有所改进,我已在
df
中添加了其他信息,用于调试,您可以根据需要删除这些信息:

import pandas as pd
from pandas_datareader import data as pdr

# download dataframe
test = pdr.get_data_yahoo("SPY", start="2000-01-01")

class Book:
    def __init__(self, stocks = 0, money = 100.0, asset = 0.0):
        self.stocks = stocks
        self.money = money
        self.asset = asset

    def buy(self, price):
        if self.money == 0:
            self.asset = price * self.stocks + self.money
            return ''

        stocks = self.money / price
        self.stocks += stocks
        self.money -= (price * stocks)
        self.asset = price * self.stocks + self.money
        return 'buy'

    def sell(self, price):
        if self.stocks == 0:
            return ''

        self.money += price * self.stocks
        self.stocks = 0
        self.asset = self.money
        return 'sell'


    def assetEvaluate(self,price):
        self.asset = self.stocks * price + self.money
        return ''


test['ma20'] = test.Close.rolling(20).mean()

def macrossover(df, book):
    result = []
    trade = ''
    for i, r in df.iterrows():
        if df.Close[i] > df.ma20[i]:
            trade = book.buy(df.Close[i])
        elif df.Close[i] < df.ma20[i]:
            trade = book.sell(df.Close[i])
        else:
            trade = book.assetEvaluate(df.Close[i])
        result.append([i, df.Close[i], df.ma20[i], book.stocks, book.money, book.asset, trade])

    df = pd.DataFrame(result, columns=['date', 'close', 'ma20', 'stocks', 'money', 'asset', 'trade'])
    df.set_index('date', inplace=True)
    print(df)

a = Book()
macrossover(test, a)
我注意到了两件事,首先是在一些计算过程中,
money
变为负值,这是因为Python中的浮点计算限制,请参阅以了解更多详细信息。如果您选择仅将
股票
作为整数,则可以在代码中解析负数
货币
,即使用运算符
/
。如果您希望将
股票
作为整数,请更新我的上述代码,并将
购买
功能替换为以下内容:

def buy(self, price):
    stocks = self.money // price
    if self.money == 0 | stocks == 0:
        self.asset = price * self.stocks + self.money
        return ''
    self.stocks += stocks
    self.money -= (price * stocks)
    self.asset = price * self.stocks + self.money
    return 'buy'
第二件事是,在
buy
功能中,当我们购买
stocks
时,
money
只需要为新的
stocks
减少,而不是为所有可用的股票减少


此外,对于使用乘法和除法的所有浮点数,可以将其舍入到小数点后两位。

我已更新了您的代码,如下所示,现在它似乎有所改进,我已在
df
中添加了其他信息,以便调试,您可以根据需要删除这些信息:

import pandas as pd
from pandas_datareader import data as pdr

# download dataframe
test = pdr.get_data_yahoo("SPY", start="2000-01-01")

class Book:
    def __init__(self, stocks = 0, money = 100.0, asset = 0.0):
        self.stocks = stocks
        self.money = money
        self.asset = asset

    def buy(self, price):
        if self.money == 0:
            self.asset = price * self.stocks + self.money
            return ''

        stocks = self.money / price
        self.stocks += stocks
        self.money -= (price * stocks)
        self.asset = price * self.stocks + self.money
        return 'buy'

    def sell(self, price):
        if self.stocks == 0:
            return ''

        self.money += price * self.stocks
        self.stocks = 0
        self.asset = self.money
        return 'sell'


    def assetEvaluate(self,price):
        self.asset = self.stocks * price + self.money
        return ''


test['ma20'] = test.Close.rolling(20).mean()

def macrossover(df, book):
    result = []
    trade = ''
    for i, r in df.iterrows():
        if df.Close[i] > df.ma20[i]:
            trade = book.buy(df.Close[i])
        elif df.Close[i] < df.ma20[i]:
            trade = book.sell(df.Close[i])
        else:
            trade = book.assetEvaluate(df.Close[i])
        result.append([i, df.Close[i], df.ma20[i], book.stocks, book.money, book.asset, trade])

    df = pd.DataFrame(result, columns=['date', 'close', 'ma20', 'stocks', 'money', 'asset', 'trade'])
    df.set_index('date', inplace=True)
    print(df)

a = Book()
macrossover(test, a)
我注意到了两件事,首先是在一些计算过程中,
money
变为负值,这是因为Python中的浮点计算限制,请参阅以了解更多详细信息。如果您选择仅将
股票
作为整数,则可以在代码中解析负数
货币
,即使用运算符
/
。如果您希望将
股票
作为整数,请更新我的上述代码,并将
购买
功能替换为以下内容:

def buy(self, price):
    stocks = self.money // price
    if self.money == 0 | stocks == 0:
        self.asset = price * self.stocks + self.money
        return ''
    self.stocks += stocks
    self.money -= (price * stocks)
    self.asset = price * self.stocks + self.money
    return 'buy'
第二件事是,在
buy
功能中,当我们购买
stocks
时,
money
只需要为新的
stocks
减少,而不是为所有可用的股票减少


此外,对于使用乘法和除法的所有浮点数,可以将四舍五入到小数点后两位。

如果您发布最小输入数据帧和预期输出数据帧,则更容易分析。请阅读。您能发布最小输入数据帧和预期输出数据帧吗?这样比较容易分析。请阅读。