File size: 6,947 Bytes
96e7d53 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
import json
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import pickle
# Function for Monte Carlo Simulation
def monte_carlo_simulation(portfolio_data, scenario_data, num_simulations=10000):
"""
Performs a Monte Carlo simulation on a portfolio based on market scenarios.
Args:
portfolio_data (dict): Dictionary of portfolio data.
scenario_data (dict): Dictionary of market scenario data.
num_simulations (int, optional): The number of simulations. Defaults to 10000.
Returns:
dict: A dictionary containing simulation results for each scenario.
"""
scenarios = scenario_data["market_scenarios"]
results = {}
for scenario_key, scenario_details in scenarios.items():
scenario_name = scenario_details["name"]
sector_impacts = scenario_details.get("sector_impact", {})
results[scenario_name] = {
"portfolio_values": [],
"average_return": 0,
"std_dev_return": 0,
"percentiles": {},
}
for _ in range(num_simulations):
portfolio_value = 0
for asset_name, asset_details in portfolio_data["assets"].items():
sector = asset_details["sector"]
quantity = asset_details["quantity"]
initial_price = asset_details["initial_price"]
price_change_percentage = 0
if sector in sector_impacts:
price_change_percentage = np.random.normal(
loc=sector_impacts[sector] / 100, scale=0.1
)
# Calculate the new price
new_price = initial_price * (1 + price_change_percentage)
portfolio_value += new_price * quantity
results[scenario_name]["portfolio_values"].append(portfolio_value)
# Calculate Results
portfolio_values = results[scenario_name]["portfolio_values"]
initial_portfolio_value = sum(
asset["quantity"] * asset["initial_price"] for asset in portfolio_data["assets"].values()
)
returns = [
(value - initial_portfolio_value) / initial_portfolio_value
for value in portfolio_values
]
results[scenario_name]["average_return"] = np.mean(returns)
results[scenario_name]["std_dev_return"] = np.std(returns)
results[scenario_name]["percentiles"] = {
5: np.percentile(returns, 5),
25: np.percentile(returns, 25),
50: np.percentile(returns, 50),
75: np.percentile(returns, 75),
95: np.percentile(returns, 95),
}
return results
if __name__ == "__main__":
# Load input data
with open("output_files/scenario.json") as f:
scenario_data = json.load(f)
with open("output_files/portfolio.json") as f:
portfolio_data = json.load(f)
# Load the dictionary from the local file
def load_dataframes(filename="output_files/saved_dataframes.pkl"):
try:
with open(filename, 'rb') as file:
saved_dataframes = pickle.load(file)
print(f"DataFrames successfully loaded from {filename}.")
return saved_dataframes
except FileNotFoundError:
print(f"File {filename} not found.")
return None
saved_dataframes = load_dataframes()
# Placeholder for storing results
scenario_results = {}
# Process each scenario
for scenario_name, scenario_details in scenario_data["market_scenarios"].items():
impacted_sectors = scenario_details["sector_impact"]
# Filter assets in the impacted sectors
relevant_assets = [
symbol
for symbol, details in portfolio_data["assets"].items()
if details["sector"] in impacted_sectors
]
# Calculate magnitudes for the scenario
sector_magnitudes = {}
for symbol in relevant_assets:
df = saved_dataframes[symbol]
sector = portfolio_data["assets"][symbol]["sector"]
# Calculate magnitude as the absolute difference between first and last Close price
magnitude = abs(df["Close"].iloc[-2] - df["Close"].iloc[-1])
# Aggregate by sector
if sector not in sector_magnitudes:
sector_magnitudes[sector] = 0
sector_magnitudes[sector] += magnitude
# Calculate aggregated magnitude for the scenario
aggregated_magnitude = sum(sector_magnitudes.values())
# Store results
scenario_results[scenario_name] = {
"individual_magnitudes": sector_magnitudes,
"aggregated_magnitude": aggregated_magnitude,
}
# Display results
for scenario_name, results in scenario_results.items():
print(f"\nScenario: {scenario_name}")
print("Individual Sector Magnitudes:")
for sector, magnitude in results["individual_magnitudes"].items():
print(f" {sector}: {magnitude:.2f}")
print(f"Aggregated Magnitude: {results['aggregated_magnitude']:.2f}")
# Integrate calculated results into scenario data
for scenario_id, results in scenario_results.items():
# Update the sector impacts to include individual magnitudes
scenario_data["market_scenarios"][scenario_id]["sector_impact"] = results["individual_magnitudes"]
# Update aggregated magnitude
scenario_data["market_scenarios"][scenario_id]["aggregated_magnitude"] = results["aggregated_magnitude"]
# Save the updated scenario data to a local JSON file
output_file_path = "output_files/updated_scenario_data.json"
with open(output_file_path, "w") as file:
json.dump(scenario_data, file, indent=4)
print(f"Updated scenario data saved to '{output_file_path}' successfully!")
# Run Monte Carlo simulation
simulation_results = monte_carlo_simulation(portfolio_data, scenario_data)
# Save simulation results to a local JSON file
simulation_results_file = "output_files/simulation_results.json"
with open(simulation_results_file, "w") as file:
json.dump(simulation_results, file, indent=4)
print(f"Simulation results saved to '{simulation_results_file}' successfully!")
# Print simulation results
for scenario_name, results in simulation_results.items():
print(f"Scenario: {scenario_name}")
print(f" Average Return: {results['average_return']:.4f}")
print(f" Std Dev Return: {results['std_dev_return']:.4f}")
print(" Return Percentiles:")
for percentile, value in results["percentiles"].items():
print(f" {percentile}th: {value:.4f}")
print("-" * 40)
|