forked from mafia23/intelligent-trading-bot
117 lines
4.8 KiB
Python
117 lines
4.8 KiB
Python
import numpy as np
| |
import pandas as pd
| |
| |
"""
| |
Backtesting and trade performance using trade simulation
| |
"""
| |
| |
def simulated_trade_performance(df, buy_signal_column, sell_signal_column, price_column):
| |
"""
| |
The function simulates trades over the time by buying and selling the asset
| |
according to the specified buy/sell signals and price. Essentially, it assumes
| |
the existence of some initial amount, then it moves forward in time by finding
| |
next buy/sell signal and accordingly buying/selling the asset using the current
| |
price. At the end, it finds how much it earned by comparing with the initial amount.
| |
| |
It returns short and long performance as a number of metrics collected during
| |
one simulation pass.
| |
"""
| |
is_buy_mode = True
| |
| |
long_profit = 0
| |
long_profit_percent = 0
| |
long_transactions = 0
| |
long_profitable = 0
| |
longs = list() # Where we buy
| |
| |
short_profit = 0
| |
short_profit_percent = 0
| |
short_transactions = 0
| |
short_profitable = 0
| |
shorts = list() # Where we sell
| |
| |
# The order of columns is important for itertuples
| |
df = df[[sell_signal_column, buy_signal_column, price_column]]
| |
for (index, sell_signal, buy_signal, price) in df.itertuples(name=None):
| |
if not price or pd.isnull(price):
| |
continue
| |
if is_buy_mode:
| |
# Check if minimum price
| |
if buy_signal:
| |
previous_price = shorts[-1][2] if len(shorts) > 0 else 0.0
| |
profit = (previous_price - price) if previous_price > 0 else 0.0
| |
profit_percent = 100.0 * profit / previous_price if previous_price > 0 else 0.0
| |
short_profit += profit
| |
short_profit_percent += profit_percent
| |
short_transactions += 1
| |
if profit > 0:
| |
short_profitable += 1
| |
shorts.append((index, previous_price, price, profit, profit_percent)) # Bought
| |
is_buy_mode = False
| |
else:
| |
# Check if maximum price
| |
if sell_signal:
| |
previous_price = longs[-1][2] if len(longs) > 0 else 0.0
| |
profit = (price - previous_price) if previous_price > 0 else 0.0
| |
profit_percent = 100.0 * profit / previous_price if previous_price > 0 else 0.0
| |
long_profit += profit
| |
long_profit_percent += profit_percent
| |
long_transactions += 1
| |
if profit > 0:
| |
long_profitable += 1
| |
longs.append((index, previous_price, price, profit, profit_percent)) # Sold
| |
is_buy_mode = True
| |
| |
# Performance of buy at low price and sell at high price
| |
long_performance = {
| |
"#transactions": long_transactions,
| |
"profit": round(long_profit, 2),
| |
"%profit": round(long_profit_percent, 1),
| |
| |
"#profitable": long_profitable,
| |
"%profitable": round(100.0 * long_profitable / long_transactions, 1) if long_transactions else 0.0,
| |
| |
"profit/T": round(long_profit / long_transactions, 2) if long_transactions else 0.0,
| |
"%profit/T": round(long_profit_percent / long_transactions, 1) if long_transactions else 0.0,
| |
| |
#"transactions": longs, # Sell transactions
| |
}
| |
| |
# Performance of sell at high price and buy at low price
| |
short_performance = {
| |
"#transactions": short_transactions,
| |
"profit": round(short_profit, 2),
| |
"%profit": round(short_profit_percent, 1),
| |
| |
"#profitable": short_profitable,
| |
"%profitable": round(100.0 * short_profitable / short_transactions, 1) if short_transactions else 0.0,
| |
| |
"profit/T": round(short_profit / short_transactions, 2) if short_transactions else 0.0,
| |
"%profit/T": round(short_profit_percent / short_transactions, 1) if short_transactions else 0.0,
| |
| |
#"transactions": shorts, # Buy transactions
| |
}
| |
| |
profit = long_profit + short_profit
| |
profit_percent = long_profit_percent + short_profit_percent
| |
transaction_no = long_transactions + short_transactions
| |
profitable = (long_profitable + short_profitable) / transaction_no if transaction_no else 0.0
| |
#minutes_in_month = 1440 * 30.5
| |
performance = {
| |
"#transactions": transaction_no,
| |
"profit": profit,
| |
"%profit": profit_percent,
| |
| |
"profitable": profitable,
| |
"profitable_percent": round(100.0 * profitable / transaction_no, 1) if transaction_no else 0.0,
| |
| |
"profit/T": round(profit / transaction_no, 2) if transaction_no else 0.0,
| |
"%profit/T": round(profit_percent / transaction_no, 1) if transaction_no else 0.0,
| |
| |
#"transactions": transactions,
| |
| |
#"profit_per_month": profit / (len(df) / minutes_in_month),
| |
#"transactions_per_month": transaction_no / (len(df) / minutes_in_month),
| |
}
| |
| |
return performance, long_performance, short_performance
|