Skip to content

Instantly share code, notes, and snippets.

@Curtis-64
Last active May 22, 2023 01:22
Show Gist options
  • Save Curtis-64/8ed2e708a24bbb18445769e27eef090d to your computer and use it in GitHub Desktop.
Save Curtis-64/8ed2e708a24bbb18445769e27eef090d to your computer and use it in GitHub Desktop.
Python Monte Carlo Trade Simulator
copy/paste into Ipython Notebook
!pip install sympy
import numpy as np
import matplotlib.pyplot as plt
from sympy import symbols, solve
# Define the symbols
P_W = symbols('P_W')
# Parameters
edge = .05
risk_reward = 2
# Solve the equation without the edge, accounting for risk_reward
zero_sum_win_ratio = solve(P_W * risk_reward - (1 - P_W), P_W)[0]
# Add the edge
win_ratio = zero_sum_win_ratio + edge
initial_equity = 2400 # initial account equity
risk_per_trade_percent = 0.05 # risk per trade as a percentage of the account equity
num_trades = 6 * 20 * 1
#num_trades = 100
trailing_dd = 2000
target = 3000
num_sims = 100
min_risk = 50 # minimum risk amount in dollars
# Initialize stats
max_drawdowns = []
average_drawdowns = []
average_returns = []
average_total_returns_no_dd = []
total_equity = 0
target_hit_counts = 0
trailing_dd_counts = 0
# Initialize a list to store all equity curves
all_equity_curves = []
# Monte Carlo simulation
for i in range(num_sims):
equity = initial_equity
high_equity = equity # Initialize high equity with initial equity
drawdown = 0
max_dd = 0
total_dd = 0
equity_curve = []
hit_trailing_dd = False # flag to track if trailing drawdown was hit in this simulation
for j in range(num_trades):
risk_per_trade = max(min_risk, equity * risk_per_trade_percent) # calculate risk per trade based on current equity
if np.random.rand() < win_ratio:
# Win trade
equity += risk_reward * risk_per_trade
else:
# Lose trade
equity -= risk_per_trade
high_equity = max(high_equity, equity) # Update high equity
drawdown = max(0, high_equity - equity) # Update drawdown
max_dd = max(max_dd, drawdown) # Update max drawdown
total_dd += drawdown
# Stop trading if trailing drawdown is hit
if drawdown >= trailing_dd:
hit_trailing_dd = True # mark that trailing drawdown was hit in this simulation
trailing_dd_counts += 1
break # stop trading for this simulation if trailing drawdown is hit
# Stop trading if target is hit
if (equity - initial_equity) >= target:
target_hit_counts += 1
break # stop trading for this simulation if target is hit
equity_curve.append(equity)
max_drawdowns.append(max_dd)
average_drawdowns.append(total_dd / num_trades)
average_returns.append((equity - initial_equity) / num_trades) # Corrected average return calculation
total_equity += equity
# Store the equity curve for this simulation along with its color
if hit_trailing_dd:
color = 'red'
elif (equity - initial_equity) >= target:
color = 'green'
else:
color = 'yellow'
all_equity_curves.append((equity_curve, color))
# Compute y-axis limits for the plots
min_equity = min(min(curve) for curve, color in all_equity_curves if curve)
max_equity = max(max(curve) for curve, color in all_equity_curves if curve)
# Plot each equity curve with the computed y-axis limits
for equity_curve, color in all_equity_curves:
if equity_curve: # check if equity_curve is not empty
plt.plot(equity_curve, color=color)
plt.ylim(min_equity, max_equity)
plt.show() # display the plot once after all curves have been plotted
# Compute stats
max_dd_avg = np.mean(max_drawdowns)
avg_dd_avg = np.mean(average_drawdowns)
avg_return_avg = np.mean(average_returns)
avg_total_return_no_dd = np.mean(average_total_returns_no_dd) if average_total_returns_no_dd else 0
average_overall_equity = total_equity / num_sims
target_hit_ratio = target_hit_counts / num_sims
trailing_dd_ratio = trailing_dd_counts / num_sims # updated to count only simulations that hit trailing drawdown
print(f'Zero Sum Win Ratio: {zero_sum_win_ratio}')
print(f'Edge: {edge}')
print(f'Win Ratio Total: {win_ratio}')
print(f'R: {risk_reward}')
print(f'% Risk: {risk_per_trade_percent}')
print(f'Target: {target}')
print(f'Trail DD: {trailing_dd}')
print(f'Min $ Risk: {min_risk}')
print(f'Number Trades: {num_trades}')
print(f'Number Sims: {num_sims}')
print(f'Average Maximum Drawdown: {max_dd_avg}')
print(f'Average Drawdown: {avg_dd_avg}')
print(f'Average Return per Trade: {avg_return_avg}')
print(f'Average Total Return (No DD Hit): {avg_total_return_no_dd}')
print(f'Average Overall Equity: {average_overall_equity}')
print(f'Target Hit Ratio: {target_hit_ratio}')
print(f'Trailing Drawdown Hit Ratio: {trailing_dd_ratio}')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment