-
Notifications
You must be signed in to change notification settings - Fork 357
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1054 from ashis2004/44
Optimizing_Dividend_Capture_Strategies_Using_Genetics_Algorithms added
- Loading branch information
Showing
3 changed files
with
312 additions
and
0 deletions.
There are no files selected for viewing
272 changes: 272 additions & 0 deletions
272
...enetics_Algorithms/Optimizing_Dividend_Capture_Strategies_Using_Genetics_Algorithms.ipynb
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,272 @@ | ||
{ | ||
"nbformat": 4, | ||
"nbformat_minor": 0, | ||
"metadata": { | ||
"colab": { | ||
"provenance": [] | ||
}, | ||
"kernelspec": { | ||
"name": "python3", | ||
"display_name": "Python 3" | ||
}, | ||
"language_info": { | ||
"name": "python" | ||
} | ||
}, | ||
"cells": [ | ||
{ | ||
"cell_type": "code", | ||
"execution_count": 1, | ||
"metadata": { | ||
"id": "mIQHuRd1S9oz" | ||
}, | ||
"outputs": [], | ||
"source": [ | ||
"import pandas as pd\n", | ||
"import numpy as np\n", | ||
"import datetime\n", | ||
"\n", | ||
"# Generate synthetic data for dividend capture strategies\n", | ||
"np.random.seed(42)\n", | ||
"dates = pd.date_range(start='2020-01-01', end='2023-12-31', freq='D')\n", | ||
"stock_prices = np.random.uniform(50, 150, len(dates))\n", | ||
"dividends = np.zeros(len(dates))\n", | ||
"dividend_dates = np.random.choice(dates, size=30, replace=False)\n", | ||
"dividends[[dates.get_loc(date) for date in dividend_dates]] = np.random.uniform(0.5, 2.0, len(dividend_dates))\n", | ||
"\n", | ||
"# Create DataFrame\n", | ||
"data_dividend = pd.DataFrame({\n", | ||
" 'Date': dates,\n", | ||
" 'Stock_Price': stock_prices,\n", | ||
" 'Dividend': dividends\n", | ||
"})\n", | ||
"\n", | ||
"# Save to CSV\n", | ||
"data_dividend.to_csv('dividend_data.csv', index=False)\n" | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"source": [ | ||
"import pandas as pd\n", | ||
"import numpy as np\n", | ||
"\n", | ||
"# Load data\n", | ||
"data_dividend = pd.read_csv('dividend_data.csv')\n", | ||
"print(data_dividend.head())\n" | ||
], | ||
"metadata": { | ||
"colab": { | ||
"base_uri": "https://localhost:8080/" | ||
}, | ||
"id": "gjjU7SRuTeQ4", | ||
"outputId": "776eb83d-9f8a-4ea6-beb4-79b033474682" | ||
}, | ||
"execution_count": 2, | ||
"outputs": [ | ||
{ | ||
"output_type": "stream", | ||
"name": "stdout", | ||
"text": [ | ||
" Date Stock_Price Dividend\n", | ||
"0 2020-01-01 87.454012 0.0\n", | ||
"1 2020-01-02 145.071431 0.0\n", | ||
"2 2020-01-03 123.199394 0.0\n", | ||
"3 2020-01-04 109.865848 0.0\n", | ||
"4 2020-01-05 65.601864 0.0\n" | ||
] | ||
} | ||
] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"source": [ | ||
"def fitness_function(individual, data):\n", | ||
" buy_signal = individual[0]\n", | ||
" sell_signal = individual[1]\n", | ||
"\n", | ||
" capital = 100000 # Starting capital\n", | ||
" position = 0\n", | ||
" returns = 0\n", | ||
"\n", | ||
" for i in range(len(data)):\n", | ||
" if data['Dividend'][i] > buy_signal and position == 0:\n", | ||
" position = capital / data['Stock_Price'][i]\n", | ||
" capital = 0\n", | ||
"\n", | ||
" if data['Dividend'][i] < sell_signal and position > 0:\n", | ||
" capital = position * data['Stock_Price'][i]\n", | ||
" returns += capital - 100000 # Net returns\n", | ||
" position = 0\n", | ||
"\n", | ||
" return returns\n" | ||
], | ||
"metadata": { | ||
"id": "gRes_Ds2Tgu5" | ||
}, | ||
"execution_count": 3, | ||
"outputs": [] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"source": [ | ||
"def initialize_population(pop_size):\n", | ||
" population = []\n", | ||
" for _ in range(pop_size):\n", | ||
" individual = np.random.uniform(0.01, 2.0, 2) # Random buy and sell signals\n", | ||
" population.append(individual)\n", | ||
" return population\n" | ||
], | ||
"metadata": { | ||
"id": "JeS6oOJ0Ti_4" | ||
}, | ||
"execution_count": 4, | ||
"outputs": [] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"source": [ | ||
"def selection(population, fitness_scores, num_parents):\n", | ||
" parents = [population[idx] for idx in np.argsort(fitness_scores)[-num_parents:]]\n", | ||
" return parents\n" | ||
], | ||
"metadata": { | ||
"id": "cIw1EoJ3TkwW" | ||
}, | ||
"execution_count": 5, | ||
"outputs": [] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"source": [ | ||
"def crossover(parents, offspring_size):\n", | ||
" offspring = []\n", | ||
" for _ in range(offspring_size):\n", | ||
" parent1 = parents[np.random.randint(len(parents))]\n", | ||
" parent2 = parents[np.random.randint(len(parents))]\n", | ||
" crossover_point = np.random.randint(1, len(parent1))\n", | ||
" child = np.concatenate((parent1[:crossover_point], parent2[crossover_point:]))\n", | ||
" offspring.append(child)\n", | ||
" return offspring\n" | ||
], | ||
"metadata": { | ||
"id": "R0iURKc-TmtA" | ||
}, | ||
"execution_count": 6, | ||
"outputs": [] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"source": [ | ||
"def mutation(offspring, mutation_rate):\n", | ||
" for individual in offspring:\n", | ||
" if np.random.rand() < mutation_rate:\n", | ||
" mutation_point = np.random.randint(len(individual))\n", | ||
" individual[mutation_point] = np.random.uniform(0.01, 2.0)\n", | ||
" return offspring\n" | ||
], | ||
"metadata": { | ||
"id": "0A3HvpApTpHS" | ||
}, | ||
"execution_count": 7, | ||
"outputs": [] | ||
}, | ||
{ | ||
"cell_type": "code", | ||
"source": [ | ||
"def genetic_algorithm(data, num_generations, pop_size, num_parents, mutation_rate):\n", | ||
" population = initialize_population(pop_size)\n", | ||
"\n", | ||
" for generation in range(num_generations):\n", | ||
" fitness_scores = [fitness_function(individual, data) for individual in population]\n", | ||
" parents = selection(population, fitness_scores, num_parents)\n", | ||
" offspring_size = pop_size - len(parents)\n", | ||
" offspring = crossover(parents, offspring_size)\n", | ||
" offspring = mutation(offspring, mutation_rate)\n", | ||
" population = parents + offspring\n", | ||
"\n", | ||
" best_fitness = np.max(fitness_scores)\n", | ||
" print(f\"Generation {generation}: Best Fitness = {best_fitness}\")\n", | ||
"\n", | ||
" best_individual = population[np.argmax(fitness_scores)]\n", | ||
" return best_individual\n", | ||
"\n", | ||
"# Run the genetic algorithm\n", | ||
"num_generations = 50\n", | ||
"pop_size = 100\n", | ||
"num_parents = 20\n", | ||
"mutation_rate = 0.01\n", | ||
"\n", | ||
"best_params = genetic_algorithm(data_dividend, num_generations, pop_size, num_parents, mutation_rate)\n", | ||
"print(f\"Best Parameters (Buy Signal, Sell Signal): {best_params}\")\n" | ||
], | ||
"metadata": { | ||
"colab": { | ||
"base_uri": "https://localhost:8080/" | ||
}, | ||
"id": "RRwHYs15Troe", | ||
"outputId": "98efbe20-c945-4bac-86bb-320dc4924314" | ||
}, | ||
"execution_count": 8, | ||
"outputs": [ | ||
{ | ||
"output_type": "stream", | ||
"name": "stdout", | ||
"text": [ | ||
"Generation 0: Best Fitness = 1065823.8186480976\n", | ||
"Generation 1: Best Fitness = 1340050.1052260087\n", | ||
"Generation 2: Best Fitness = 1340050.1052260087\n", | ||
"Generation 3: Best Fitness = 1340050.1052260087\n", | ||
"Generation 4: Best Fitness = 1340050.1052260087\n", | ||
"Generation 5: Best Fitness = 1340050.1052260087\n", | ||
"Generation 6: Best Fitness = 1340050.1052260087\n", | ||
"Generation 7: Best Fitness = 1340050.1052260087\n", | ||
"Generation 8: Best Fitness = 1340050.1052260087\n", | ||
"Generation 9: Best Fitness = 1340050.1052260087\n", | ||
"Generation 10: Best Fitness = 1340050.1052260087\n", | ||
"Generation 11: Best Fitness = 1340050.1052260087\n", | ||
"Generation 12: Best Fitness = 1340050.1052260087\n", | ||
"Generation 13: Best Fitness = 1340050.1052260087\n", | ||
"Generation 14: Best Fitness = 1340050.1052260087\n", | ||
"Generation 15: Best Fitness = 1340050.1052260087\n", | ||
"Generation 16: Best Fitness = 1340050.1052260087\n", | ||
"Generation 17: Best Fitness = 1340050.1052260087\n", | ||
"Generation 18: Best Fitness = 1340050.1052260087\n", | ||
"Generation 19: Best Fitness = 1340050.1052260087\n", | ||
"Generation 20: Best Fitness = 1340050.1052260087\n", | ||
"Generation 21: Best Fitness = 1340050.1052260087\n", | ||
"Generation 22: Best Fitness = 1340050.1052260087\n", | ||
"Generation 23: Best Fitness = 1340050.1052260087\n", | ||
"Generation 24: Best Fitness = 1340050.1052260087\n", | ||
"Generation 25: Best Fitness = 1340050.1052260087\n", | ||
"Generation 26: Best Fitness = 1340050.1052260087\n", | ||
"Generation 27: Best Fitness = 1340050.1052260087\n", | ||
"Generation 28: Best Fitness = 1340050.1052260087\n", | ||
"Generation 29: Best Fitness = 1340050.1052260087\n", | ||
"Generation 30: Best Fitness = 1340050.1052260087\n", | ||
"Generation 31: Best Fitness = 1340050.1052260087\n", | ||
"Generation 32: Best Fitness = 1340050.1052260087\n", | ||
"Generation 33: Best Fitness = 1340050.1052260087\n", | ||
"Generation 34: Best Fitness = 1340050.1052260087\n", | ||
"Generation 35: Best Fitness = 1340050.1052260087\n", | ||
"Generation 36: Best Fitness = 1340050.1052260087\n", | ||
"Generation 37: Best Fitness = 1340050.1052260087\n", | ||
"Generation 38: Best Fitness = 1340050.1052260087\n", | ||
"Generation 39: Best Fitness = 1340050.1052260087\n", | ||
"Generation 40: Best Fitness = 1340050.1052260087\n", | ||
"Generation 41: Best Fitness = 1340050.1052260087\n", | ||
"Generation 42: Best Fitness = 1340050.1052260087\n", | ||
"Generation 43: Best Fitness = 1340050.1052260087\n", | ||
"Generation 44: Best Fitness = 1340050.1052260087\n", | ||
"Generation 45: Best Fitness = 1340050.1052260087\n", | ||
"Generation 46: Best Fitness = 1340050.1052260087\n", | ||
"Generation 47: Best Fitness = 1340050.1052260087\n", | ||
"Generation 48: Best Fitness = 1340050.1052260087\n", | ||
"Generation 49: Best Fitness = 1340050.1052260087\n", | ||
"Best Parameters (Buy Signal, Sell Signal): [0.49135888 1.6493184 ]\n" | ||
] | ||
} | ||
] | ||
} | ||
] | ||
} |
33 changes: 33 additions & 0 deletions
33
Optimizing_Dividend_Capture_Strategies_Using_Genetics_Algorithms/readme.md
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# Optimizing Dividend Capture Strategies Using Genetic Algorithms | ||
|
||
This project focuses on optimizing dividend capture strategies through the use of genetic algorithms. Dividend capture strategy involves buying a stock just before its ex-dividend date and selling it after the dividend is paid out. The objective is to maximize the returns by optimizing the entry and exit points and other parameters using genetic algorithms. | ||
|
||
## Table of Contents | ||
|
||
- [Introduction](#introduction) | ||
- [Requirements](#requirements) | ||
- [Installation](#installation) | ||
- [Usage](#usage) | ||
- [Dataset](#dataset) | ||
- [Methodology](#methodology) | ||
- [Results](#results) | ||
|
||
## Introduction | ||
|
||
Dividend capture strategy aims to exploit the predictable drop in stock prices after the dividend is paid out. By using genetic algorithms, we can optimize the parameters involved in this strategy to maximize returns. Genetic algorithms simulate the process of natural selection by generating a population of potential solutions and evolving them over multiple generations. | ||
|
||
## Requirements | ||
|
||
- Python 3.8+ | ||
- pandas | ||
- numpy | ||
- matplotlib | ||
- deap (Distributed Evolutionary Algorithms in Python) | ||
|
||
Methodology | ||
Initialization: Generate an initial population of potential solutions. | ||
Evaluation: Evaluate the fitness of each solution based on the returns of the dividend capture strategy. | ||
Selection: Select the best-performing solutions to form a new population. | ||
Crossover: Combine pairs of solutions to create offspring with mixed characteristics. | ||
Mutation: Introduce random changes to some solutions to maintain diversity. | ||
Iteration: Repeat the evaluation, selection, crossover, and mutation steps for multiple generations. |
7 changes: 7 additions & 0 deletions
7
Optimizing_Dividend_Capture_Strategies_Using_Genetics_Algorithms/requirement.txt
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
## Requirements | ||
|
||
- Python 3.8+ | ||
- pandas | ||
- numpy | ||
- matplotlib | ||
- deap (Distributed Evolutionary Algorithms in Python) |