psemdel / py-trading-bot

Trading-bot in python using django, vertorbt lib and interactive-brokers
MIT License
141 stars 34 forks source link

Add strat #31

Closed webbuilderhero closed 9 months ago

webbuilderhero commented 1 year ago

I have a simple strat boilerplate im using for quant im wondering if you can port it over to your framework so I can use my strats on your bot. I am having a hard time grasping everything going on with your setup. import pandas as pd import yfinance as yf import numpy as np import matplotlib.pyplot as plt from scipy.signal import morlet

Download historical data for S&P 500 from Yahoo Finance

df = yf.download('^GSPC', start='2010-01-01', end='2023-06-23')

Use adjusted close prices

df['close'] = df['Adj Close']

Apply discrete Morlet wavelet transform

def wavelet_transform(signal, window_size): wavelet = morlet(window_size, 5) transformed_signal = np.convolve(signal, wavelet, mode='same') return transformed_signal

df['wavelet'] = wavelet_transform(df['close'], window_size=51)

Calculate differences to identify up and down movements

df['price_diff'] = df['close'].diff()

Separate into monotonic states

df['up'] = df['price_diff'].clip(lower=0) df['down'] = df['price_diff'].clip(upper=0) * -1

Initialize columns for normalized up and down movements

df['up_norm'] = 0.0 df['down_norm'] = 0.0

Compute ranks using the entire price data

df['up_norm'] = df['up'].rank(pct=True) df['down_norm'] = df['down'].rank(pct=True)

Calculate log returns

df['log_returns'] = np.log(df['close']).diff()

Define position sizing model

positionSizingModel = 'percentage' # Choose the position sizing model ('percentage', 'fixed_ratio', 'secure_f', 'margin_based')

Position sizing parameters

accountEquity = 100000 # Account equity riskPercentage = 1.5 # Risk percentage per trade stopLossPips = 250 # Stop loss in pips percentageVolatility = 2.5 # Percentage volatility model fixedRatio = 0.02 # Fixed ratio model secureF = 0.01 # Secure (f) model marginBasedSize = 0.01 # Margin-based size model

Calculate position size

contractSize = 5000
accountSize = accountEquity * riskPercentage / 100.0

if positionSizingModel == 'percentage': positionSize = accountSize percentageVolatility / (stopLossPips contractSize) elif positionSizingModel == 'fixed_ratio': positionSize = accountEquity fixedRatio / (stopLossPips contractSize) elif positionSizingModel == 'secure_f': positionSize = accountEquity secureF / (stopLossPips contractSize) elif positionSizingModel == 'margin_based': margin = accountEquity * marginBasedSize positionSize = margin / stopLossPips

print("Position Size:", positionSize)

Define trading logic

df['position_size'] = np.where(df['up_norm'] > 0.95, positionSize, np.where(df['down_norm'] > 0.95, -positionSize, np.nan)) df['position_size'] = df['position_size'].fillna(method='ffill')

Compute returns

df['returns'] = df['log_returns'] * df['position_size']

Calculate equity curve

df['equity_curve'] = (df['returns'] + 1).cumprod() * accountEquity

Plot equity curve with 'Close' price

fig, ax1 = plt.subplots(figsize=(10, 5))

ax1.plot(df.index, df['equity_curve'], color='blue', label='Equity Curve') ax1.set_xlabel('Date') ax1.set_ylabel('Equity', color='blue') ax1.set_title('Equity Curve and Close Price') ax1.tick_params('y', colors='blue')

ax2 = ax1.twinx() ax2.plot(df.index, df['close'], color='red', label='Close Price') ax2.set_ylabel('Close Price', color='red') ax2.tick_params('y', colors='red')

fig.tight_layout()

Add legend

lines_1, labels_1 = ax1.get_legend_handles_labels() lines_2, labels_2 = ax2.get_legend_handles_labels() lines = lines_1 + lines_2 labels = labels_1 + labels_2 plt.legend(lines, labels)

plt.show()

psemdel commented 1 year ago

Hi, thx for the suggestion. I can definitely understand that it is still a bit difficult to understand everything. I am working on it, but there is still a long way.

Basically, for 80% of what you write should go in core/indicator, where the vector calculations are performed. You can have a look at VBTSUPERTREND, it was coded directly by vbt author. The indicator uses normally only numpy functions to be faster. So it performs on each symbol separately. But of course, you could do a fit of post processing with pandas, if you want.

To download historical data, go in core/data_manager. all_symbols=constants.NYSE index="^GSPC" It will save two files in core: actions (so here the NYSE prices) and index (^GSPC). I see here, the first small issue. Vbt does not seem to implement the column "Adj Close". Let's use "Close" instead.

My bot is also design to perform automatic orders depending on clear signal. Not to plot curve, that you need to read manually.

I will try to implement your strategy. I cannot promess, in which month to be honest. I am in the middle of a total reworking of the core of the code, it will take me a while.

psemdel commented 12 months ago

I wrote it, but I cannot see how to decide which order. Also the wavelet is not used? Actually the return calculation and so on is taken care by vbt. You just need to define the entries and exits. I suppose it related to equity_curve != NaN ?