Ошибка в тесте пересечения скользящих средних панд - PullRequest
0 голосов
/ 20 сентября 2018

Я пытаюсь протестировать стратегию пересечения скользящих средних с пандами.

Сначала я определил класс (Book), где количество акций, сумма наличных и общая сумма актива.

В классе есть 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)

результат

                 close    stocks         money       asset
date                                                      
1999-12-31  146.875000  0.000000  1.000000e+02  100.000000
2000-01-03  145.437500  0.000000  1.000000e+02  100.000000
2000-01-04  139.750000  0.000000  1.000000e+02  100.000000
2000-01-05  140.000000  0.000000  1.000000e+02  100.000000
2000-01-06  137.750000  0.000000  1.000000e+02  100.000000
2000-01-07  145.750000  0.000000  1.000000e+02  100.000000
2000-01-10  146.250000  0.000000  1.000000e+02  100.000000
2000-01-11  144.500000  0.000000  1.000000e+02  100.000000
2000-01-12  143.062500  0.000000  1.000000e+02  100.000000
2000-01-13  145.000000  0.000000  1.000000e+02  100.000000
2000-01-14  146.968704  0.000000  1.000000e+02  100.000000
2000-01-18  145.812500  0.000000  1.000000e+02  100.000000
2000-01-19  147.000000  0.000000  1.000000e+02  100.000000
2000-01-20  144.750000  0.000000  1.000000e+02  100.000000
2000-01-21  144.437500  0.000000  1.000000e+02  100.000000
2000-01-24  140.343704  0.000000  1.000000e+02  100.000000
2000-01-25  141.937500  0.000000  1.000000e+02  100.000000
2000-01-26  140.812500  0.000000  1.000000e+02  100.000000
2000-01-27  140.250000  0.000000  1.000000e+02  100.000000
2000-01-28  135.875000  0.000000  1.000000e+02  100.000000
2000-01-31  139.562500  0.000000  1.000000e+02  100.000000
2000-02-01  140.937500  0.000000  1.000000e+02  100.000000
2000-02-02  141.062500  0.000000  1.000000e+02  100.000000
2000-02-03  143.187500  0.698385  0.000000e+00  100.000000
2000-02-04  142.593704  0.000000  9.958530e+01   99.585302
2000-02-07  142.375000  0.000000  9.958530e+01   99.585302
2000-02-08  144.312500  0.690067  1.421085e-14   99.585302
2000-02-09  141.281204  0.000000  9.749350e+01   97.493505
2000-02-10  141.562500  0.000000  9.749350e+01   97.493505
2000-02-11  138.687500  0.000000  9.749350e+01   97.493505
               ...       ...           ...         ...
2018-08-08  285.459991  0.002378  0.000000e+00    0.654858
2018-08-09  285.070007  0.002378  0.000000e+00    0.654858
2018-08-10  283.160004  0.002378  0.000000e+00    0.654858
2018-08-13  282.100006  0.000000  6.707412e-01    0.670741
2018-08-14  283.899994  0.002363  0.000000e+00    0.670741
2018-08-15  281.779999  0.000000  6.657325e-01    0.665732
2018-08-16  284.059998  0.002344  0.000000e+00    0.665732
2018-08-17  285.059998  0.002344  0.000000e+00    0.665732
2018-08-20  285.670013  0.002344  0.000000e+00    0.665732
2018-08-21  286.339996  0.002344  0.000000e+00    0.665732
2018-08-22  286.170013  0.002344  0.000000e+00    0.665732
2018-08-23  285.790009  0.002344  0.000000e+00    0.665732
2018-08-24  287.510010  0.002344  0.000000e+00    0.665732
2018-08-27  289.779999  0.002344  0.000000e+00    0.665732
2018-08-28  289.920013  0.002344  0.000000e+00    0.665732
2018-08-29  291.480011  0.002344  0.000000e+00    0.665732
2018-08-30  290.299988  0.002344  0.000000e+00    0.665732
2018-08-31  290.309998  0.002344  0.000000e+00    0.665732
2018-09-04  289.809998  0.002344  0.000000e+00    0.665732
2018-09-05  289.029999  0.002344  0.000000e+00    0.665732
2018-09-06  288.160004  0.002344  0.000000e+00    0.665732
2018-09-07  287.600006  0.002344  0.000000e+00    0.665732
2018-09-10  288.100006  0.002344  0.000000e+00    0.665732
2018-09-11  289.049988  0.002344  0.000000e+00    0.665732
2018-09-12  289.119995  0.002344  0.000000e+00    0.665732
2018-09-13  290.829987  0.002344  0.000000e+00    0.665732
2018-09-14  290.880005  0.002344  0.000000e+00    0.665732
2018-09-17  289.339996  0.002344  0.000000e+00    0.665732
2018-09-18  290.910004  0.002344  0.000000e+00    0.665732
2018-09-19  291.220001  0.002344  0.000000e+00    0.665732

1 Ответ

0 голосов
/ 22 сентября 2018

Я обновил ваш код, как показано ниже, и теперь он выглядит несколько лучше и улучшен. Я добавил дополнительную информацию в 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)

И выходной фрейм данных теперь такой, как показано ниже:

                 close        ma20    stocks         money       asset trade
date                                                                        
1999-12-31  146.875000         NaN  0.000000  1.000000e+02  100.000000      
2000-01-03  145.437500         NaN  0.000000  1.000000e+02  100.000000      
2000-01-04  139.750000         NaN  0.000000  1.000000e+02  100.000000      
2000-01-05  140.000000         NaN  0.000000  1.000000e+02  100.000000      
2000-01-06  137.750000         NaN  0.000000  1.000000e+02  100.000000      
2000-01-07  145.750000         NaN  0.000000  1.000000e+02  100.000000      
2000-01-10  146.250000         NaN  0.000000  1.000000e+02  100.000000      
2000-01-11  144.500000         NaN  0.000000  1.000000e+02  100.000000      
2000-01-12  143.062500         NaN  0.000000  1.000000e+02  100.000000      
2000-01-13  145.000000         NaN  0.000000  1.000000e+02  100.000000      
2000-01-14  146.968704         NaN  0.000000  1.000000e+02  100.000000      
2000-01-18  145.812500         NaN  0.000000  1.000000e+02  100.000000      
2000-01-19  147.000000         NaN  0.000000  1.000000e+02  100.000000      
2000-01-20  144.750000         NaN  0.000000  1.000000e+02  100.000000      
2000-01-21  144.437500         NaN  0.000000  1.000000e+02  100.000000      
2000-01-24  140.343704         NaN  0.000000  1.000000e+02  100.000000      
2000-01-25  141.937500         NaN  0.000000  1.000000e+02  100.000000      
2000-01-26  140.812500         NaN  0.000000  1.000000e+02  100.000000      
2000-01-27  140.250000         NaN  0.000000  1.000000e+02  100.000000      
2000-01-28  135.875000  143.128120  0.000000  1.000000e+02  100.000000      
2000-01-31  139.562500  142.762495  0.000000  1.000000e+02  100.000000      
2000-02-01  140.937500  142.537495  0.000000  1.000000e+02  100.000000      
2000-02-02  141.062500  142.603120  0.000000  1.000000e+02  100.000000      
2000-02-03  143.187500  142.762495  0.698385  0.000000e+00  100.000000   buy
2000-02-04  142.593704  143.004681  0.000000  9.958530e+01   99.585302  sell
2000-02-07  142.375000  142.835931  0.000000  9.958530e+01   99.585302      
2000-02-08  144.312500  142.739056  0.690067  1.421085e-14   99.585302   buy
2000-02-09  141.281204  142.578116  0.000000  9.749350e+01   97.493505  sell
2000-02-10  141.562500  142.503116  0.000000  9.749350e+01   97.493505      
2000-02-11  138.687500  142.187491  0.000000  9.749350e+01   97.493505      
...                ...         ...       ...           ...         ...   ...
2018-08-10  283.160004  282.158501  0.377979  0.000000e+00  107.028495      
2018-08-13  282.100006  282.296501  0.000000  1.066278e+02  106.627838  sell
2018-08-14  283.899994  282.468001  0.375582  0.000000e+00  106.627838   buy
2018-08-15  281.779999  282.504001  0.000000  1.058316e+02  105.831606  sell
2018-08-16  284.059998  282.707001  0.372568  0.000000e+00  105.831606   buy
2018-08-17  285.059998  282.976001  0.372568  0.000000e+00  106.204173      
2018-08-20  285.670013  283.249501  0.372568  0.000000e+00  106.431446      
2018-08-21  286.339996  283.486002  0.372568  0.000000e+00  106.681060      
2018-08-22  286.170013  283.594002  0.372568  0.000000e+00  106.617729      
2018-08-23  285.790009  283.716502  0.372568  0.000000e+00  106.476152      
2018-08-24  287.510010  284.021002  0.372568  0.000000e+00  107.116969      
2018-08-27  289.779999  284.512502  0.372568  0.000000e+00  107.962694      
2018-08-28  289.920013  284.942003  0.372568  0.000000e+00  108.014859      
2018-08-29  291.480011  285.473004  0.372568  0.000000e+00  108.596064      
2018-08-30  290.299988  285.868503  0.372568  0.000000e+00  108.156425      
2018-08-31  290.309998  286.204002  0.372568  0.000000e+00  108.160154      
2018-09-04  289.809998  286.462502  0.372568  0.000000e+00  107.973870      
2018-09-05  289.029999  286.635002  0.372568  0.000000e+00  107.683268      
2018-09-06  288.160004  286.770003  0.372568  0.000000e+00  107.359136      
2018-09-07  287.600006  286.896503  0.372568  0.000000e+00  107.150499      
2018-09-10  288.100006  287.143503  0.372568  0.000000e+00  107.336783      
2018-09-11  289.049988  287.491002  0.372568  0.000000e+00  107.690715      
2018-09-12  289.119995  287.752002  0.372568  0.000000e+00  107.716798      
2018-09-13  290.829987  288.204501  0.372568  0.000000e+00  108.353885      
2018-09-14  290.880005  288.545502  0.372568  0.000000e+00  108.372521      
2018-09-17  289.339996  288.759502  0.372568  0.000000e+00  107.798763      
2018-09-18  290.910004  289.021501  0.372568  0.000000e+00  108.383697      
2018-09-19  291.220001  289.265501  0.372568  0.000000e+00  108.499192      
2018-09-20  293.579987  289.636000  0.372568  0.000000e+00  109.378447      
2018-09-21  292.040009  289.948500  0.372568  0.000000e+00  108.804701    

Я заметил несколько вещей, во-первых, во время некоторых вычислений money становится отрицательным, это из-за ограничений вычисления с плавающей запятой вPython, см. Арифметика с плавающей запятой: проблемы и ограничения для получения более подробной информации.Отрицательный money может быть разрешен в вашем коде, если вы решите использовать только stocks в качестве целого числа, что можно сделать, используя разделение по полу , то есть с оператором //.Если вы хотите получить stocks как целое число, обновите мой код выше и замените функцию buy на следующую:

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 при покупке stocksmoney нужно уменьшить только для нового stocks, а не для всего доступного.

Дополнительно можно выполнить округление до двух десятичных разрядов для всех плавающих чисел, где умножение и деление с использованием округляют (число[, ndigits]) .

Надеюсь, это поможет вам в некоторой степени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...