Advertisement
dravitch

momentum_strategy_analysis_and_simulation_tool.py

Jan 3rd, 2025
56
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.85 KB | Cryptocurrency | 0 0
  1. """
  2. Cryptocurrency Momentum Strategy Analysis and Simulation Tool
  3.  
  4. WARNING: THIS SCRIPT IS PROVIDED FOR EDUCATIONAL PURPOSES ONLY.
  5. THIS IS NOT FINANCIAL ADVICE. CRYPTOCURRENCY INVESTMENTS ARE HIGHLY
  6. VOLATILE AND INVOLVE SIGNIFICANT RISKS. ALWAYS CONDUCT YOUR OWN
  7. RESEARCH AND CONSULT A QUALIFIED FINANCIAL ADVISOR BEFORE MAKING
  8. ANY INVESTMENT DECISIONS.
  9.  
  10. Description:
  11. This script enables users to:
  12. - Analyze historical cryptocurrency performance
  13. - Implement an advanced momentum strategy
  14. - Compare different strategy configurations
  15. - Visualize performance results
  16.  
  17. Key Features:
  18. - Historical data download via yfinance
  19. - Momentum calculation across different periods
  20. - Selection of best-performing cryptocurrencies based on momentum
  21. - Portfolio simulation with annual rebalancing
  22. - Comparative performance visualization
  23.  
  24. Dependencies:
  25. - numpy
  26. - pandas
  27. - matplotlib
  28. - yfinance
  29. - tabulate
  30. """
  31.  
  32. import numpy as np
  33. import pandas as pd
  34. import matplotlib.pyplot as plt
  35. import yfinance as yf
  36. from tabulate import tabulate
  37.  
  38. class EnhancedMomentumStrategy:
  39.     def __init__(self, tickers, start_date, end_date, initial_investment=100000,
  40.                  momentum_window=12, top_n_cryptos=3):
  41.         self.tickers = tickers
  42.         self.start_date = start_date
  43.         self.end_date = end_date
  44.         self.initial_investment = initial_investment
  45.         self.momentum_window = momentum_window
  46.         self.top_n_cryptos = top_n_cryptos
  47.  
  48.     def download_crypto_data(self):
  49.         """
  50.        Downloads historical cryptocurrency data with robust error handling
  51.        """
  52.         try:
  53.             data = yf.download(self.tickers, start=self.start_date, end=self.end_date)['Adj Close']
  54.             data = data.ffill().bfill()
  55.             return data
  56.         except Exception as e:
  57.             print(f"Error downloading data: {e}")
  58.             return None
  59.  
  60.     def calculate_momentum(self, data):
  61.         """
  62.        Calculates momentum with proper handling of missing data
  63.        """
  64.         if data is None or data.empty:
  65.             return None
  66.  
  67.         # Calculate momentum as percentage change over specified window
  68.         momentum = data.pct_change(periods=self.momentum_window) * 100
  69.         momentum = momentum.fillna(0)
  70.  
  71.         return momentum
  72.  
  73.     def select_top_momentum_cryptos(self, momentum):
  74.         """
  75.        Selects top cryptocurrencies based on momentum
  76.        """
  77.         if momentum is None or momentum.empty:
  78.             return None
  79.  
  80.         # Use last row of momentum data, sort and select top N
  81.         try:
  82.             return momentum.iloc[-1].sort_values(ascending=False).head(self.top_n_cryptos)
  83.         except Exception as e:
  84.             print(f"Error selecting top cryptos: {e}")
  85.             return None
  86.  
  87.     def simulate_portfolio(self):
  88.         """
  89.        Simulates portfolio strategy with comprehensive error handling
  90.        """
  91.         # Download price data
  92.         data = self.download_crypto_data()
  93.  
  94.         if data is None or data.empty:
  95.             print("No data available for simulation.")
  96.             return None
  97.  
  98.         portfolio_value = self.initial_investment
  99.         portfolio_history = [portfolio_value]
  100.  
  101.         # Simulate for each year
  102.         years_to_simulate = range(int(self.start_date[:4]), min(int(self.end_date[:4]) + 1, 2025))
  103.  
  104.         for year in years_to_simulate:
  105.             year_start = f"{year}-01-01"
  106.             year_end = f"{year}-12-31"
  107.  
  108.             # Calculate momentum and select top cryptos
  109.             yearly_data = data.loc[:year_end]
  110.             yearly_momentum = self.calculate_momentum(yearly_data)
  111.  
  112.             if yearly_momentum is None:
  113.                 print(f"Unable to calculate momentum for {year}")
  114.                 continue
  115.  
  116.             top_cryptos = self.select_top_momentum_cryptos(yearly_momentum)
  117.  
  118.             if top_cryptos is None or len(top_cryptos) == 0:
  119.                 print(f"No top cryptos found for {year}")
  120.                 continue
  121.  
  122.             # Allocate portfolio equally among top cryptos
  123.             allocation_per_crypto = portfolio_value / len(top_cryptos)
  124.  
  125.             # Calculate year-end portfolio value
  126.             year_end_values = {}
  127.             for crypto in top_cryptos.index:
  128.                 try:
  129.                     # Use first available price of the year
  130.                     current_price = yearly_data.loc[year_start:, crypto].iloc[0]
  131.                     crypto_shares = allocation_per_crypto / current_price
  132.  
  133.                     # Calculate year-end value
  134.                     year_end_price = yearly_data.loc[year_start:year_end, crypto].iloc[-1]
  135.                     year_end_values[crypto] = crypto_shares * year_end_price
  136.                 except Exception as e:
  137.                     print(f"Unable to calculate value for {crypto}: {e}")
  138.  
  139.             # Update portfolio value
  140.             if year_end_values:
  141.                 portfolio_value = sum(year_end_values.values())
  142.                 portfolio_history.append(portfolio_value)
  143.  
  144.         # Performance calculations
  145.         if len(portfolio_history) > 1:
  146.             total_return = (portfolio_history[-1] - self.initial_investment) / self.initial_investment * 100
  147.  
  148.             return {
  149.                 'initial_investment': self.initial_investment,
  150.                 'final_value': portfolio_history[-1],
  151.                 'total_return_percent': total_return,
  152.                 'top_cryptos': list(top_cryptos.index)
  153.             }
  154.         else:
  155.             print("Insufficient data for performance calculation")
  156.             return None
  157.  
  158. def compare_momentum_strategies(strategies_params):
  159.     """
  160.    Compares multiple momentum strategy configurations
  161.    """
  162.     comparison_results = []
  163.  
  164.     for params in strategies_params:
  165.         strategy = EnhancedMomentumStrategy(**params)
  166.         performance = strategy.simulate_portfolio()
  167.  
  168.         if performance:
  169.             result = {
  170.                 'Momentum Window': params.get('momentum_window', 'N/A'),
  171.                 'Top N Cryptos': params.get('top_n_cryptos', 'N/A'),
  172.                 'Initial Investment': f"${performance['initial_investment']:,.2f}",
  173.                 'Final Value': f"${performance['final_value']:,.2f}",
  174.                 'Total Return (%)': f"{performance['total_return_percent']:.2f}%",
  175.                 'Top Cryptocurrencies': ', '.join(performance['top_cryptos'])
  176.             }
  177.             comparison_results.append(result)
  178.  
  179.     return comparison_results
  180.  
  181. def main():
  182.     # Complete list of cryptocurrencies
  183.     cryptos = [
  184.         'BTC-USD', 'ETH-USD', 'BNB-USD', 'ADA-USD', 'DOT-USD',
  185.         'LTC-USD', 'SOL-USD', 'LINK-USD', 'DOGE-USD', 'XRP-USD',
  186.         'AVAX-USD', 'UNI-USD', 'ATOM-USD', 'ALGO-USD', 'MANA-USD'
  187.     ]
  188.  
  189.     # Define different strategy parameter configurations
  190.     strategies_params = [
  191.         {
  192.             'tickers': cryptos,
  193.             'start_date': '2020-01-01',
  194.             'end_date': '2024-12-31',
  195.             'initial_investment': 100000,
  196.             'momentum_window': window,
  197.             'top_n_cryptos': top_n
  198.         }
  199.         for window in [6, 12, 18]
  200.         for top_n in [3, 5, 7]
  201.     ]
  202.  
  203.     # Compare strategies
  204.     results = compare_momentum_strategies(strategies_params)
  205.  
  206.     # Display results
  207.     print(tabulate(results, headers="keys", tablefmt="pretty"))
  208.  
  209.     # Performance visualization
  210.     if results:
  211.         plt.figure(figsize=(12, 6))
  212.         returns = [float(result['Total Return (%)'].strip('%')) for result in results]
  213.         labels = [f"MW{result['Momentum Window']}\nTop{result['Top N Cryptos']}" for result in results]
  214.  
  215.         plt.bar(labels, returns)
  216.         plt.title('Comparison of Momentum Strategy Performances')
  217.         plt.ylabel('Total Return (%)')
  218.         plt.xlabel('Strategy Configuration')
  219.         plt.xticks(rotation=45, ha='right')
  220.         plt.tight_layout()
  221.         plt.show()
  222.  
  223. if __name__ == "__main__":
  224.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement