Skip to content

Instantly share code, notes, and snippets.

@miohtama
Created November 8, 2023 22:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save miohtama/c947d54cfa066932c64005e833d7f4c2 to your computer and use it in GitHub Desktop.
Save miohtama/c947d54cfa066932c64005e833d7f4c2 to your computer and use it in GitHub Desktop.
Trading signal vs. price movement vs. profit analysis using Pandas
def calculate_signal_vs_profit(
df,
signal_window: pd.Timedelta,
profit_window: pd.Timedelta,
data_time_bucket: pd.Timedelta,
) -> pd.DataFrame:
"""Calculate signals and profits for all incoming candles."""
# Create entries for past price to be used for signal
# and future price (used for the price correlation)
signal_offset = to_offset(signal_window)
profit_offset = to_offset(profit_window)
df["prev"] = df["close"].shift(freq=signal_offset)
df["next"] = df["open"].shift(freq=-profit_offset)
# Calculate signal from the past and price difference to the future
df["signal"] = (df["prev"] - df["open"]) / df["open"]
df["price_diff"] = (df["next"] - df["open"]) / df["open"] # Get the profit on the final day of profit window
# On negative signals, we go short.
# On zero signal and lack of data set side to NA
df["side"] = pd.NA
df.loc[df["signal"] > 0, "side"] = "long"
df.loc[df["signal"] < 0, "side"] = "short"
number_of_candles = profit_window / data_time_bucket
assert number_of_candles > 0 and number_of_candles.is_integer(), f"Could not calculate candle count that fits into profit window {profit_window} for data time frame {data_time_bucket}"
number_of_candles = int(number_of_candles)
# Max and min price wihtin the profit window will determine the profit for longs and shorts respective
df["max_future_price"] = df["close"].rolling(number_of_candles).max().shift(-number_of_candles) # Get the max profit on the profit window, assuming take profit %
df["min_future_price"] = df["close"].rolling(number_of_candles).min().shift(-number_of_candles) # Get the max profit on the profit window, assuming take profit %
# Calculate profit separately for longs and shorts
# using Pandas Mask
# https://stackoverflow.com/a/33770421/315168
#
# We calculate both profit after X time,
# and also max take profit, assuming
# we could do a perfect trailing stop loss
#
longs = (df["side"] == "long")
shorts = (df["side"] == "short")
df.loc[longs, "profit"] = df["price_diff"]
df.loc[shorts, "profit"] = -df["price_diff"]
df.loc[longs, "profit_max"] = (df["max_future_price"] - df["open"]) / df["open"] # Get the profit based on max price
df.loc[shorts, "profit_max"] = -(df["min_future_price"] - df["open"]) / df["open"] # Get the profit based on max price
df.loc[longs, "desc"] = df.agg('{0[pair]} long'.format, axis=1)
df.loc[shorts, "desc"] = df.agg('{0[pair]} short'.format, axis=1)
return df
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment