Created
November 8, 2023 22:33
-
-
Save miohtama/c947d54cfa066932c64005e833d7f4c2 to your computer and use it in GitHub Desktop.
Trading signal vs. price movement vs. profit analysis using Pandas
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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