The Real Traders Aren't on CNBC
Your current options for finding stock trades:
Option 1: Spend 4 hours daily reading everything online
Option 2: Pay $500/month for paywalled newsletters and pray
Option 3: Get yesterday's news from mainstream financial media
All three keep you broke.
Here's where the actual edge lives:
Twitter traders sharing real setups (not TV personalities)
Crowdfunding opportunities before they go mainstream
IPO alerts with actual timing
Reddit communities spotting trends early
Crypto insider takes (not corporate PR)
The problem? You'd need to be terminally online to track it all.
Stocks & Income monitors every corner where real money gets made. We send you only the actionable opportunities. No fluff, no yesterday's headlines.
Five minutes daily. Walk away with stock insights you can actually act on every time.
Stocks & Income is for informational purposes only and is not intended to be used as investment advice. Do your own research.
🚀 Your Investing Journey Just Got Better: Premium Subscriptions Are Here! 🚀
It’s been 4 months since we launched our premium subscription plans at GuruFinance Insights, and the results have been phenomenal! Now, we’re making it even better for you to take your investing game to the next level. Whether you’re just starting out or you’re a seasoned trader, our updated plans are designed to give you the tools, insights, and support you need to succeed.
Here’s what you’ll get as a premium member:
Exclusive Trading Strategies: Unlock proven methods to maximize your returns.
In-Depth Research Analysis: Stay ahead with insights from the latest market trends.
Ad-Free Experience: Focus on what matters most—your investments.
Monthly AMA Sessions: Get your questions answered by top industry experts.
Coding Tutorials: Learn how to automate your trading strategies like a pro.
Masterclasses & One-on-One Consultations: Elevate your skills with personalized guidance.
Our three tailored plans—Starter Investor, Pro Trader, and Elite Investor—are designed to fit your unique needs and goals. Whether you’re looking for foundational tools or advanced strategies, we’ve got you covered.
Don’t wait any longer to transform your investment strategy. The last 4 months have shown just how powerful these tools can be—now it’s your turn to experience the difference.

Buy and Sell Signals of Tesla
Introduction
Systematic trading strategies live at the intersection of finance and data science. Rather than relying on gut feeling, these approaches define clear rules for entering and exiting trades.
But even with a robust idea, the real challenge lies in selecting the right parameters:
How long should the lookback window be?
What threshold should signal a buy or a sell?
This is where Bayesian optimization becomes invaluable. Instead of blindly testing every possible parameter combination, Bayesian methods allow us to intelligently search the parameter space and converge on configurations that improve strategy performance.
In this article, we’ll build and optimize a Rate of Change (ROC) trading strategy. We’ll use Tesla’s stock data (TSLA), calculate buy and sell signals from ROC, and apply Bayesian optimization to discover the most profitable configuration.
By the end, you’ll see how the optimized strategy compares against a simple buy-and-hold approach.
Run ads IRL with AdQuick
With AdQuick, you can now easily plan, deploy and measure campaigns just as easily as digital ads, making them a no-brainer to add to your team’s toolbox.
You can learn more at www.AdQuick.com
Background on the Strategy
The Rate of Change (ROC) is a momentum oscillator that measures the percentage change in price over a given number of periods. It helps identify when momentum is accelerating or decelerating:
High positive ROC suggests strong upward momentum.
Negative ROC can signal weakness or a potential reversal.
Our trading logic will be:
Buy when the ROC rises above a positive threshold.
Sell when the ROC falls below a negative threshold.
Instead of guessing the optimal lookback period or thresholds, we’ll let Bayesian optimization handle the search for us.
Installing Dependencies
We begin by installing the necessary Python packages. These include:
yfinance
for fetching stock datapandas
for data manipulationmatplotlib
for visualizationta
for technical indicatorsbayesian-optimization
for the optimization process, andtabulate
for clean summaries.
%pip install yfinance bayesian-optimization matplotlib pandas ta tabulate --quiet
Importing Libraries
Next, we import the libraries.
import yfinance as yf
import matplotlib.pyplot as plt
from ta.momentum import ROCIndicator
from bayes_opt import BayesianOptimization
from tabulate import tabulate
Loading Tesla Stock Data
We’ll fetch Tesla’s daily closing prices from January 2020 to December 2024. This dataset will form the foundation for our backtest.
# Load Tesla stock data
symbol = 'TSLA'
initial_cash = 1 # Initial cash for backtesting
data = yf.download(symbol, start='2020-01-01', end='2024-12-31')
data.columns = data.columns.get_level_values(0)
data = data[['Close']]
data.dropna(inplace=True)
data.head()
Visualizing the Closing Price
Before diving into strategies, it’s useful to visualize the stock’s chart.
# Visualize the closing price of the stock
plt.figure(figsize=(14,6))
plt.plot(data.index, data['Close'], label=f'{symbol} Closing Price', color='blue')
plt.title(f'{symbol} Closing Price (2020–2024)')
plt.xlabel('Date')
plt.ylabel('Price (USD)')
plt.grid(True)
plt.legend()
plt.savefig('closing_price.png', dpi=300, bbox_inches='tight')
plt.show()

TSLA Closing Price
Splitting the Data
To avoid overfitting, we split the data into training (70%) and testing (30%). Optimization will be run on the training set, and evaluation will take place on the test set.
# Train-test split (70% train, 30% test)
train_size = int(len(data) * 0.7)
train_data = data.iloc[:train_size].copy()
test_data = data.iloc[train_size:].copy()
print(f"Training from {train_data.index[0]} to {train_data.index[-1]}")
print(f"Testing from {test_data.index[0]} to {test_data.index[-1]}")
Training from 2020-01-02 00:00:00 to 2023-06-29 00:00:00
Testing from 2023-06-30 00:00:00 to 2024-12-30 00:00:00
Backtesting the Strategy
We define a backtest function to simulate trades. It calculates ROC values, executes buy/sell logic, tracks portfolio value, and records trade signals.
def backtest_strategy(df, roc_window, buy_threshold, sell_threshold):
df = df.copy()
roc_window = int(roc_window)
buy_threshold = float(buy_threshold)
sell_threshold = float(sell_threshold)
roc = ROCIndicator(close=df['Close'], window=roc_window)
df['ROC'] = roc.roc()
position = 0
cash = initial_cash
portfolio = []
trades = 0
buy_signals = []
sell_signals = []
for i in range(roc_window, len(df)):
if df['ROC'].iloc[i] > buy_threshold and position == 0:
position = cash / df['Close'].iloc[i]
cash = 0
buy_signals.append((df.index[i], df['Close'].iloc[i]))
trades += 1
elif df['ROC'].iloc[i] < sell_threshold and position > 0:
cash = position * df['Close'].iloc[i]
position = 0
sell_signals.append((df.index[i], df['Close'].iloc[i]))
trades += 1
portfolio_value = cash + (position * df['Close'].iloc[i])
portfolio.append(portfolio_value)
final_value = cash + position * df['Close'].iloc[-1]
return_percentage = (final_value - initial_cash) / initial_cash * 100
return return_percentage, trades, buy_signals, sell_signals, portfolio
Defining the Optimization Objective
The optimizer needs a function that maps strategy parameters to performance. Here, the objective is to maximize returns.
Wall Street’s Morning Edge.
Investing isn’t about chasing headlines — it’s about clarity. In a world of hype and hot takes, The Daily Upside delivers real value: sharp, trustworthy insights on markets, business, and the economy, written by former bankers and seasoned financial journalists.
That’s why over 1 million investors — from Wall Street pros to Main Street portfolio managers — start their day with The Daily Upside.
Invest better. Read The Daily Upside.
def objective(roc_window, buy_threshold, sell_threshold):
returns, _, _, _, _ = backtest_strategy(train_data, roc_window, buy_threshold, sell_threshold)
return returns
Bayesian Optimization Setup
We now specify the search space:
ROC window between 3 and 30 days.
Buy threshold between 0.1% and 10%.
Sell threshold between -10% and -0.1%.
The optimizer will explore these ranges to identify the best-performing parameters.
pbounds = {
'roc_window': (3, 30),
'buy_threshold': (0.1, 10),
'sell_threshold': (-10, -0.1)
}
optimizer = BayesianOptimization(
f=objective,
pbounds=pbounds,
random_state=42,
verbose=2
)
optimizer.maximize(init_points=5, n_iter=20)
best_params = optimizer.max['params']
best_params
Applying the Best Parameters
With the optimized values, we backtest again on the test set to see real-world applicability.
best_roc = int(best_params['roc_window'])
best_buy = float(best_params['buy_threshold'])
best_sell = float(best_params['sell_threshold'])
returns, trades, buy_signals, sell_signals, portfolio = backtest_strategy(
test_data, best_roc, best_buy, best_sell
)
print(f"Final Return on Test Set: {returns:.2f}%")
print(f"Number of Trades: {trades}")
Final Return on Test Set: 46.51%
Number of Trades: 15
Comparing to Buy and Hold
To understand if the strategy adds value, we compare its portfolio curve against a simple buy-and-hold.
# Visualize portfolio value vs. buy-and-hold on the test set
df = test_data.copy()
df = df.iloc[best_roc:].copy() # Skip rows lost due to ROC calculation
# Strategy Portfolio Value
df['Strategy'] = portfolio
# Buy-and-hold simulation
initial_price = df['Close'].iloc[0]
df['BuyHold'] = (df['Close'] / initial_price) * initial_cash
# Plot both
plt.figure(figsize=(14,6))
plt.plot(df.index, df['Strategy'], label='ROC Strategy', color='orange', linewidth=2)
plt.plot(df.index, df['BuyHold'], label='Buy & Hold', color='green', linewidth=2)
plt.title('ROC Strategy vs. Buy & Hold (Test Set)')
plt.xlabel('Date')
plt.ylabel('Portfolio Value ($)')
plt.legend()
plt.grid(True)
plt.savefig('portfolio_comparison.png', dpi=300, bbox_inches='tight')
plt.show()

Visualizing Buy and Sell Signals
Charts make it easier to evaluate whether entry and exit points align with meaningful price moves.
# Plot buy/sell signals on test set
plt.figure(figsize=(14,6))
# Plot the closing price first
plt.plot(test_data.index, test_data['Close'], label='Price', color='blue', zorder=1)
# Plot buy signals
for buy in buy_signals:
plt.scatter(buy[0], buy[1], marker='^', color='lime', s=100, label='Buy Signal', zorder=2)
# Plot sell signals
for sell in sell_signals:
plt.scatter(sell[0], sell[1], marker='v', color='red', s=100, label='Sell Signal', zorder=2)
# Only show each label once
handles, labels = plt.gca().get_legend_handles_labels()
by_label = dict(zip(labels, handles))
plt.legend(by_label.values(), by_label.keys())
plt.title('Buy/Sell Signals on Test Set')
plt.xlabel('Date')
plt.ylabel('Price')
plt.grid(True)
plt.savefig('buy_sell_signals.png', dpi=300, bbox_inches='tight')
plt.show()

Evaluating Strategy Performance
Finally, we summarize results such as returns, trades, and win rate in a table. This allows a structured comparison against buy-and-hold.
# Strategy evaluation
total_trades = len(buy_signals) + len(sell_signals)
if len(buy_signals) == len(sell_signals):
successful_trades = sum(
sell[1] > buy[1] for buy, sell in zip(buy_signals, sell_signals)
)
win_rate = f"{(successful_trades / len(sell_signals) * 100):.2f}%"
else:
win_rate = 'Inconsistent buy/sell pairs'
test_df = test_data.copy().iloc[best_roc:].copy() # align with portfolio calculation start
initial_price = test_df['Close'].iloc[0]
final_price = test_df['Close'].iloc[-1]
final_strategy_value = portfolio[-1]
final_bh_value = (final_price / initial_price) * initial_cash
bh_return_pct = (final_bh_value - initial_cash) / initial_cash * 100
strategy_return_pct = (final_strategy_value - initial_cash) / initial_cash * 100
summary = [
["Initial Cash", f"${initial_cash}", f"${initial_cash}"],
["Final Portfolio Value", f"${final_strategy_value:.2f}", f"${final_bh_value:.2f}"],
["Total Return (%)", f"{strategy_return_pct:.2f}%", f"{bh_return_pct:.2f}%"],
["Total Trades Executed", total_trades, "N/A"],
["Buy Trades", len(buy_signals), "N/A"],
["Sell Trades", len(sell_signals), "N/A"],
["Win Rate", win_rate, "N/A"]
]
print(tabulate(summary, headers=["Metric", "ROC Strategy", "Buy & Hold"], tablefmt="rounded_grid"))
╭───────────────────────┬─────────────────────────────┬──────────────╮
│ Metric │ ROC Strategy │ Buy & Hold │
├───────────────────────┼─────────────────────────────┼──────────────┤
│ Initial Cash │ $1 │ $1 │
├───────────────────────┼─────────────────────────────┼──────────────┤
│ Final Portfolio Value │ $1.47 │ $1.57 │
├───────────────────────┼─────────────────────────────┼──────────────┤
│ Total Return (%) │ 46.51% │ 57.35% │
├───────────────────────┼─────────────────────────────┼──────────────┤
│ Total Trades Executed │ 15 │ N/A │
├───────────────────────┼─────────────────────────────┼──────────────┤
│ Buy Trades │ 8 │ N/A │
├───────────────────────┼─────────────────────────────┼──────────────┤
│ Sell Trades │ 7 │ N/A │
├───────────────────────┼─────────────────────────────┼──────────────┤
│ Win Rate │ Inconsistent buy/sell pairs │ N/A │
╰───────────────────────┴─────────────────────────────┴──────────────╯
A Step Toward Smarter Strategy Design
This experiment demonstrates the value of combining technical indicators with machine learning techniques.
The ROC strategy, enhanced through Bayesian optimization, highlights how parameter tuning can significantly change outcomes.
While the approach doesn’t guarantee profitability across all markets or timeframes, it illustrates a disciplined framework for research.
From here, this same methodology can be applied to other indicators such as RSI, MACD, or Bollinger Bands, broadening the toolkit while relying on Bayesian optimization to do the heavy lifting.