完整代码在这里:https://colab.research.google.com/drive/1OrtnNwAb9e1-F5f9fqI1x11fiws-GD3y?usp=sharing在此处可以看到更多详细信息。
编辑版本:https://colab.research.google.com/drive/1CHrtsOlTPsWNrva7bKtS6iIoMZPzymSl?usp=sharing
主类代码:(这是精简版)
class Strategies(object):
"""
basic class for PatternFinder.
"""
def __init__(self,
ticker='AAPL',
days_undo=100,
df=np.nan,
interval='1m',
*args,
**kwargs):
self.ticker = ticker
self.days_undo = days_undo
self.drop = 0
self.interval = interval
if df is np.nan:
data = get_data(ticker, days_undo)
self.df = data.reset_index()
else:
self.df = df.reset_index()
self.df = self.df[self.drop:].reset_index()
if interval == '1m':
self.profit_calculate_coef = 1 / 60 / 24 / 365
elif interval == '1d':
self.profit_calculate_coef = 1 / 365
else:
raise ValueError('I N C O R R E C T I N T E R V A L')
def __repr__(self):
return 'trader'
def __iter__(self):
try:
return iter(list(self.backtest_out.values))
except AttributeError:
raise ValueError('D O B A C K T E S T')
def kalman_filter(self, iters=40, plot=True, *args, **kwargs):
k_filter = KalmanFilter()
filtered = k_filter.filter(np.array(self.df['Close']))[0]
for i in range(iters):
filtered = k_filter.smooth(filtered)[0]
if plot:
self.fig.add_trace(
go.Line(
name='kalman filter',
y=filtered,
line=dict(width=SUB_LINES_WIDTH)), 1, 1)
return pd.DataFrame(filtered)
def linear_(self, dataset):
"""
linear data. mean + (mean diff * n)
"""
data = pd.DataFrame(dataset)
mean = float(data.mean())
mean_diff = float(data.diff().mean())
start = mean - (mean_diff * (len(data) / 2))
end = start + (mean - start) * 2
length = len(data)
ret = []
mean_diff = (end - start) / length
for i in range(length):
ret.append(start + mean_diff * i)
return np.array(ret)
def get_stop_take(self, sig):
"""
calculating stop loss and take profit.
sig: | int | signsl to sell/buy/exit:
2 -- exit.
1 -- buy.
0 -- sell.
"""
if self.stop_loss is not np.inf:
_stop_loss = self.stop_loss / 10_000 * self.open_price
else:
_stop_loss = np.inf
if self.take_profit is not np.inf:
take = self.take_profit / 10_000 * self.open_price
else:
take = np.inf
if sig == 1:
_stop_loss = self.open_price - _stop_loss
take = self.open_price + take
elif sig == 0:
take = self.open_price - take
_stop_loss = self.open_price + _stop_loss
else:
if self.take_profit is not np.inf:
take = self.open_price
if self.stop_loss is not np.inf:
_stop_loss = self.open_price
return {'stop': _stop_loss, 'take': take}
def strategy_parabolic_SAR(self, plot=True, *args, **kwargs):
ret = []
sar = ta.trend.PSARIndicator(self.df['High'], self.df['Low'],
self.df['Close'])
sardown = sar.psar_down()[self.drop:].values
sarup = sar.psar_up()[self.drop:].values
if plot:
for SAR_ in (sarup, sardown):
self.fig.add_trace(
go.Line(
name='SAR', y=SAR_, line=dict(width=SUB_LINES_WIDTH)),
1, 1)
for price, up, down in zip(
list(self.df['Close'].values), list(sarup), list(sardown)):
numup = np.nan_to_num(up, nan=-9999)
numdown = np.nan_to_num(down, nan=-9999)
if numup != -9999:
ret.append(1)
elif numdown != -9999:
ret.append(0)
else:
ret.append(2)
self.returns = ret
return ret
def basic_backtest(self,
deposit=10_000,
credit_leverage=1,
bet=None,
commission=0,
stop_loss=None,
take_profit=None,
plot=True,
print_out=True,
column='Close',
*args,
**kwargs):
"""
testing the strategy.
deposit: | int, float. | start deposit.
-----------------+-------------+--------------------------------------
credit_leverage: | int, float. | tradeing leverage. 1 = none
-----------------+-------------+--------------------------------------
bet: | int, float, | fixed bet to trade. None = all moneys
-----------------+-------------+--------------------------------------
commission: | int, float. | percentage commission (0 -- 100)
-----------------+-------------+--------------------------------------
stop_loss: | int, float. | stop loss in points
-----------------+-------------+--------------------------------------
take_profit: | int, float. | take profit in points
-----------------+-------------+--------------------------------------
plot: | bool. | plotting
-----------------+-------------+--------------------------------------
print_out: | bool. | printing
-----------------+-------------+--------------------------------------
column: | str | column of dataframe to becktest
returns: pd.DataFrame with data of:
signals,
deposit'
stop loss,
take profit,
linear deposit,
<<column>> price,
open bet\lot\deal price.
"""
if stop_loss is None:
self.stop_loss = np.inf
else:
self.stop_loss = stop_loss
if take_profit is None:
self.take_profit = np.inf
else:
self.take_profit = take_profit
saved_del = self.returns[len(self.returns) - 1]
if set_(self.returns)[len(self.returns) - 1] is np.nan:
self.returns[len(self.returns) - 1] = 'r'
loc = list(self.df[column][self.drop:].values)
if plot:
self.fig.add_candlestick(
close=self.df['Close'],
high=self.df['High'],
low=self.df['Low'],
open=self.df['Open'],
row=1,
col=1,
name=self.ticker)
__predictions = {}
for e, i in enumerate(set_(self.returns)):
if i is not np.nan:
__predictions[e] = i
# marker's 'y' cordinate on real price of stock/forex
if plot:
if i == 0:
self.fig.add_scatter(
name='Sell',
y=[loc[e]],
x=[e],
row=1,
col=1,
line=dict(color='#FF0000'),
marker=dict(
symbol='triangle-down',
size=SCATTER_SIZE,
opacity=SCATTER_ALPHA))
elif i == 1:
self.fig.add_scatter(
name='Buy',
y=[loc[e]],
x=[e],
row=1,
col=1,
line=dict(color='#00FF00'),
marker=dict(
symbol='triangle-up',
size=SCATTER_SIZE,
opacity=SCATTER_ALPHA))
elif i == 2:
self.fig.add_scatter(
name='Exit',
y=[loc[e]],
x=[e],
row=1,
col=1,
line=dict(color='#2a00ff'),
marker=dict(
symbol='triangle-left',
size=SCATTER_SIZE,
opacity=SCATTER_ALPHA))
sigs = list(__predictions.values())
vals = list(__predictions.keys())
self.moneys = deposit
leverage = credit_leverage
rate = bet
commission = commission
money_start = self.moneys
resur = [self.moneys]
self.losses = 0
self.trades = 0
self.open_lot_prices = []
stop_losses = []
take_profits = []
exit = False
e = 0
for enum, (val, val2, sig) in enumerate(
zip(vals[:len(vals) - 1], vals[1:], sigs[:len(sigs) - 1])):
mons = self.moneys
coef = self.moneys / loc[val]
self.open_price = loc[val]
_rate = self.moneys if rate is None else rate
if rate is not None:
if _rate >= rate:
_rate = self.moneys
_rate -= _rate * (commission / 100)
for i in (
pd.DataFrame(loc).diff().values * coef)[val + 1:val2 + 1]:
min_price = self.df['Low'][self.drop:][e]
max_price = self.df['High'][self.drop:][e]
self.open_lot_prices.append(self.open_price)
take_stop = self.get_stop_take(sig)
_stop_loss = take_stop['stop']
take = take_stop['take']
stop_losses.append(_stop_loss)
take_profits.append(take)
cond = min(_stop_loss, take) < loc[e] < max(_stop_loss, take)
if cond and not exit:
if sig == 0:
self.moneys -= i[0] * leverage * (_rate / mons)
resur.append(self.moneys)
elif sig == 1:
self.moneys += i[0] * leverage * (_rate / mons)
resur.append(self.moneys)
elif sig == 2:
resur.append(self.moneys)
else:
exit = True
resur.append(self.moneys)
e += 1
self.trades += 1
if self.moneys < mons:
self.losses += 1
exit = False
if plot:
if self.take_profit != np.inf:
self.fig.add_trace(
go.Line(
y=take_profits,
line=dict(width=TAKE_STOP_OPN_WIDTH, color=G),
opacity=STOP_TAKE_OPN_ALPHA,
name='take profit'), 1, 1)
if self.stop_loss != np.inf:
self.fig.add_trace(
go.Line(
y=stop_losses,
line=dict(width=TAKE_STOP_OPN_WIDTH, color=R),
opacity=STOP_TAKE_OPN_ALPHA,
name='stop loss'), 1, 1)
self.fig.add_trace(
go.Line(
y=self.open_lot_prices,
line=dict(width=TAKE_STOP_OPN_WIDTH, color=B),
opacity=STOP_TAKE_OPN_ALPHA,
name='open lot'), 1, 1)
self.returns[len(self.returns) - 1] = saved_del
if set_(self.returns)[len(self.returns) - 1] is np.nan:
stop_losses.append(_stop_loss)
take_profits.append(take)
self.open_lot_prices.append(self.open_price)
else:
sig = sigs[len(sigs) - 1]
take_stop = self.get_stop_take(sig)
_stop_loss = take_stop['stop']
take = take_stop['take']
stop_losses.append(_stop_loss)
take_profits.append(take)
self.open_lot_prices.append(loc[len(loc) - 1])
linear_dat = self.linear_(resur)
if plot:
self.fig.add_trace(
go.Line(
y=resur,
line=dict(color=COLOR_DEPOSIT),
name=f'D E P O S I T (S T A R T: ${money_start})'), 2, 1)
self.fig.add_trace(go.Line(y=linear_dat, name='L I N E A R'), 2, 1)
for e, i in enumerate(resur):
if i < 0:
self.fig.add_scatter(
y=[i],
x=[e],
row=2,
col=1,
line=dict(color=R),
marker=dict(
symbol='triangle-down',
size=SCATTER_SIZE,
opacity=SCATTER_DEPO_ALPHA))
start = linear_dat[0]
end = linear_dat[len(linear_dat) - 1]
self.year_profit = (end - start) / start * 100
self.year_profit /= len(resur) * self.profit_calculate_coef
if start < 0 < end:
self.year_profit = -self.year_profit
elif start > end and self.year_profit > 0:
self.year_profit = -self.year_profit
elif start < end and self.year_profit < 0:
self.year_profit = -self.year_profit
self.linear = linear_dat
self.profits = self.trades - self.losses
if print_out:
print(f'L O S S E S: {self.losses}')
print(f'T R A D E S: {self.trades}')
print(f'P R O F I T S: {self.profits}')
print(
'M E A N P E R C E N T A G E Y E A R P R O F I T: ',
self.year_profit,
'%',
sep='')
if plot:
self.fig.show()
self.stop_losses = stop_losses
self.take_profits = take_profits
self.backtest_out = pd.DataFrame(
(resur, stop_losses, take_profits, self.returns,
self.open_lot_prices, loc, self.linear),
index=[
f'deposit ({column})', 'stop loss', 'take profit',
'predictions', 'open deal/lot', column,
f"linear deposit data ({column})"
]).T.dropna()
return self.backtest_out
第二次使用basic_backtest时发生错误。我尝试使用此:
rets = self.returns
fig = self.fig
self = PatternFinder(self.ticker,
self.days_undo,
self.df,
self.interval,
self.rounding)
self.returns = rets
self.fig = fig
self = copy.deepcopy(self)
但是如果用作函数,它将无法正常工作。而且它总是会引发这种异常。
<ipython-input-40-e9c111bf303a> in <module>
1287 #trader.inverse_strategy()
1288 trader.log_data()
-> 1289 resur1 = trader.backtest()
1 frames
<ipython-input-40-e9c111bf303a> in backtest(self, deposit, credit_leverage, bet, commission, stop_loss, take_profit, plot, print_out, *args, **kwargs)
1106 plot=False,
1107 print_out=False,
-> 1108 column=column)
1109 ret_frame[f'deposit ({column})'] = returns[f'deposit ({column})']
1110 ret_frame[column] = returns[column]
<ipython-input-40-e9c111bf303a> in basic_backtest(self, deposit, credit_leverage, bet, commission, stop_loss, take_profit, plot, print_out, column, *args, **kwargs)
774
775
--> 776 linear_dat = self.linear(resur)
777 if plot:
778 self.fig.add_trace(
TypeError: 'numpy.ndarray' object is not callable
答案 0 :(得分:0)
好像您用一个numpy数组替换了self
范围内的函数。对self.linear
的发生情况进行快速分析,我猜想下面的一行是导致此问题的原因:
self.linear = linear_dat
它位于basic_backtest
函数的定义中。