├── docs ├── .gitkeep └── jpmorgan.jpg ├── assets_to_calculate.txt ├── pyastrotrader ├── transits │ ├── __init__.py │ └── transits.py ├── swisseph │ ├── seas_12.se1 │ ├── seas_18.se1 │ ├── semo_12.se1 │ ├── semo_18.se1 │ ├── sepl_12.se1 │ └── sepl_18.se1 ├── test │ ├── default_config.json │ ├── GuilhermeBenckeNatal.json │ └── default_parameters.json ├── calculate │ ├── __init__.py │ └── calculate.py ├── __init__.py ├── utils │ └── __init__.py ├── constants.py └── config.py ├── notebooks ├── config │ ├── default_config.json │ └── default_parameters.json ├── settings.py ├── DownloadData.ipynb ├── helpers.py ├── Predict.price.change.ipynb ├── Predict.swing.trade.ipynb ├── CreateModel.swing.trade.ipynb └── CreateModel.price.change.ipynb ├── run_all.sh ├── .gitignore ├── clean_notebooks.sh ├── start_notebooks.sh ├── run_notebooks.sh ├── test └── test_calculate.py ├── requirements.txt ├── run_notebooks_multiple.sh └── README.md /docs/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets_to_calculate.txt: -------------------------------------------------------------------------------- 1 | PETR4.SA 2 | VALE3.SA 3 | ITUB4.SA 4 | BBDC4.SA 5 | ABEV3.SA 6 | -------------------------------------------------------------------------------- /docs/jpmorgan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbencke/pyAstroTrader/HEAD/docs/jpmorgan.jpg -------------------------------------------------------------------------------- /pyastrotrader/transits/__init__.py: -------------------------------------------------------------------------------- 1 | from .transits import calculate_aspects, calculate_transits, get_degrees 2 | -------------------------------------------------------------------------------- /pyastrotrader/swisseph/seas_12.se1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbencke/pyAstroTrader/HEAD/pyastrotrader/swisseph/seas_12.se1 -------------------------------------------------------------------------------- /pyastrotrader/swisseph/seas_18.se1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbencke/pyAstroTrader/HEAD/pyastrotrader/swisseph/seas_18.se1 -------------------------------------------------------------------------------- /pyastrotrader/swisseph/semo_12.se1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbencke/pyAstroTrader/HEAD/pyastrotrader/swisseph/semo_12.se1 -------------------------------------------------------------------------------- /pyastrotrader/swisseph/semo_18.se1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbencke/pyAstroTrader/HEAD/pyastrotrader/swisseph/semo_18.se1 -------------------------------------------------------------------------------- /pyastrotrader/swisseph/sepl_12.se1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbencke/pyAstroTrader/HEAD/pyastrotrader/swisseph/sepl_12.se1 -------------------------------------------------------------------------------- /pyastrotrader/swisseph/sepl_18.se1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gbencke/pyAstroTrader/HEAD/pyastrotrader/swisseph/sepl_18.se1 -------------------------------------------------------------------------------- /notebooks/config/default_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "postype": "truegeo", 3 | "zodiactype": "normal", 4 | "siderealmode": "FAGAN_BRADLEY", 5 | "house_system": "P" 6 | } 7 | -------------------------------------------------------------------------------- /pyastrotrader/test/default_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "postype": "truegeo", 3 | "zodiactype": "normal", 4 | "siderealmode": "FAGAN_BRADLEY", 5 | "house_system": "P" 6 | } 7 | -------------------------------------------------------------------------------- /run_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for i in $(cat ./assets_to_calculate.txt) 4 | do 5 | echo "Processing:$i" 6 | export ASSET_TO_CALCULATE=$i 7 | ./run_notebooks.sh 8 | done 9 | 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | env/ 2 | notebooks/.ipynb_checkpoints/ 3 | notebooks/input/.ipynb_checkpoints/ 4 | .idea/ 5 | notebooks/output/ 6 | notebooks/*.html 7 | notebooks/input/ 8 | __pycache__/ 9 | start.txt 10 | end.txt 11 | 12 | -------------------------------------------------------------------------------- /pyastrotrader/test/GuilhermeBenckeNatal.json: -------------------------------------------------------------------------------- 1 | { 2 | "chart_name": "Guilherme Bencke Natal Chart", 3 | "date": "1976-12-07T12:30:00-03:00", 4 | "latitude": "-30.03", 5 | "longitude": "-51.2204", 6 | "altitude": "0" 7 | } 8 | -------------------------------------------------------------------------------- /clean_notebooks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source env/bin/activate 4 | 5 | for i in notebooks/*.ipynb 6 | do 7 | echo "Cleaning:$i" 8 | jupyter nbconvert --ClearOutputPreprocessor.enabled=True --inplace $i 9 | done 10 | 11 | -------------------------------------------------------------------------------- /pyastrotrader/calculate/__init__.py: -------------------------------------------------------------------------------- 1 | from .calculate import calculate_main_chart, calculate_planets 2 | from .calculate import calculate_iflag, generate_chart, load_config 3 | from .calculate import get_degree 4 | 5 | __all__ = [ 6 | calculate_main_chart, calculate_planets, calculate_iflag, generate_chart, 7 | load_config, get_degree 8 | ] 9 | -------------------------------------------------------------------------------- /pyastrotrader/__init__.py: -------------------------------------------------------------------------------- 1 | from pyastrotrader.calculate import load_config, generate_chart, get_degree 2 | from pyastrotrader.transits import calculate_aspects 3 | from pyastrotrader.transits import calculate_transits 4 | from pyastrotrader.transits import get_degrees 5 | 6 | from .config import check_input 7 | 8 | 9 | def show_usage(): 10 | pass 11 | 12 | 13 | def calculate_chart(input_json): 14 | input_data = check_input(input_json) 15 | config = load_config(input_data) 16 | output = generate_chart(config, input_data) 17 | return output 18 | 19 | 20 | __all__ = ['calculate_transits', 'calculate_chart', 'calculate_aspects', 21 | 'get_degrees','get_degree'] 22 | -------------------------------------------------------------------------------- /pyastrotrader/utils/__init__.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | import json 3 | 4 | 5 | def create_input_json(date_to_use, parameters_json, config_json): 6 | input_json = {} 7 | input = { 8 | "chart_name": "PETROBRAS", 9 | "date": date_to_use, 10 | "latitude": "-22.54", 11 | "longitude": "-43.14", 12 | "altitude": "0" 13 | } 14 | 15 | with open(parameters_json) as fjson: 16 | parameters = json.load(fjson) 17 | input_json['parameters'] = parameters 18 | 19 | with open(config_json) as fjson: 20 | config = json.load(fjson) 21 | input_json['config'] = config 22 | 23 | input_json['chart'] = input 24 | return input_json 25 | -------------------------------------------------------------------------------- /start_notebooks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z '$ASSET_TO_CALCULATE' ] 4 | then 5 | echo 'Please set the ASSET_TO_CALCULATE environment variable' 6 | exit -1 7 | fi 8 | 9 | #Create a virtualenv if it doesnt exist 10 | if [ ! -d "./env" ]; then 11 | virtualenv -p python3 env 12 | source env/bin/activate 13 | pip install -r requirements.txt 14 | mkdir -p notebooks/input 15 | mkdir -p notebooks/output 16 | else 17 | source env/bin/activate 18 | fi 19 | 20 | #Load the virtualenv created 21 | 22 | export PYTHONPATH=$PYTHOPATH:$PWD:$PWD/notebooks 23 | export SWISSEPH_PATH=$PWD/pyastrotrader/swisseph 24 | 25 | #Start the jupyter lab... 26 | cd notebooks 27 | jupyter lab --ip='*' --port=8080 --no-browser 28 | -------------------------------------------------------------------------------- /run_notebooks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z '$ASSET_TO_CALCULATE' ] 4 | then 5 | echo 'Please set the ASSET_TO_CALCULATE environment variable' 6 | exit -1 7 | fi 8 | 9 | if [ -z '$ALPHAVANTAGE_KEY' ] 10 | then 11 | echo 'Please set the ALPHAVANTAGE_KEY environment variable' 12 | exit -1 13 | fi 14 | 15 | #Create a virtualenv if it doesnt exist 16 | if [ ! -d "./env" ]; then 17 | virtualenv -p python3 env 18 | source env/bin/activate 19 | pip install -r requirements.txt 20 | else 21 | source env/bin/activate 22 | fi 23 | 24 | #Load the virtualenv created 25 | 26 | export PYTHONPATH=$PYTHOPATH:$PWD:$PWD/notebooks 27 | export SWISSEPH_PATH=$PWD/pyastrotrader/swisseph 28 | 29 | cd notebooks 30 | 31 | jupyter nbconvert --ExecutePreprocessor.timeout=-1 --execute DownloadData.ipynb 32 | jupyter nbconvert --ExecutePreprocessor.timeout=-1 --execute CreateModel.ipynb 33 | jupyter nbconvert --ExecutePreprocessor.timeout=-1 --execute Predict.ipynb 34 | 35 | cd .. 36 | 37 | source ./clean_notebooks.sh 38 | -------------------------------------------------------------------------------- /test/test_calculate.py: -------------------------------------------------------------------------------- 1 | import pprint 2 | 3 | from pyastrotrader import calculate_chart 4 | from pyastrotrader import calculate_aspects 5 | from pyastrotrader import calculate_transits 6 | from pyastrotrader.utils import create_input_json 7 | from pyastrotrader.constants import * 8 | 9 | if __name__ == "__main__": 10 | parameters_json = "../pyastrotrader/test/default_parameters.json" 11 | config_json = "../pyastrotrader/test/default_config.json" 12 | main_chart_input_json = create_input_json('1953-10-03T19:05:00-03:00', parameters_json, config_json) 13 | petr4_chart = calculate_chart(main_chart_input_json) 14 | 15 | today_date = "2019-12-23T05:00:00-03:00" 16 | today_chart_input_json = create_input_json(today_date, parameters_json, config_json) 17 | today_chart = calculate_chart(today_chart_input_json) 18 | 19 | planets_to_aspect = [SUN, MOON, JUPITER, SATURN] 20 | aspects_to_calculate = [CONJUNCTION, SEMISQUARE, SEXTILE, SQUARE, TRINE, OPPOSITION] 21 | 22 | pp = pprint.PrettyPrinter(depth=6) 23 | 24 | detected_aspects = calculate_aspects(petr4_chart, planets_to_aspect, aspects_to_calculate, 4) 25 | # pp.pprint(detected_aspects) 26 | 27 | detected_transits = calculate_transits(petr4_chart, today_chart, planets_to_aspect, aspects_to_calculate, 4) 28 | pp.pprint(detected_transits) 29 | -------------------------------------------------------------------------------- /pyastrotrader/constants.py: -------------------------------------------------------------------------------- 1 | SUN = 0 2 | MOON = 1 3 | MERCURY = 2 4 | VENUS = 3 5 | MARS = 4 6 | JUPITER = 5 7 | SATURN = 6 8 | URANUS = 7 9 | NEPTUNE = 8 10 | PLUTO = 9 11 | MEAN_NODE = 10 12 | TRUE_NODE = 11 13 | MEAN_APOGEE = 12 14 | OSC_APOGEE = 13 15 | EARTH = 14 16 | CHIRON = 15 17 | PHOLUS = 16 18 | CERES = 17 19 | PALLAS = 18 20 | JUNO = 19 21 | VESTA = 20 22 | INTP_APOGEE = 21 23 | INTP_PERIGEE = 22 24 | ASC = 23 25 | MC = 24 26 | DSC = 25 27 | IC = 26 28 | DAY_PARS = 27 29 | NIGHT_PARS = 28 30 | SOUTH_NODE = 29 31 | MARRIAGE_PARS = 30 32 | BLACK_SUN = 31 33 | VULCANUS = 32 34 | PERSEPHONE = 33 35 | TRUE_LILITH = 34 36 | 37 | PLANETS = [ 38 | 'SUN', 'MOON', 'MERCURY', 'VENUS', 'MARS', 'JUPITER', 'SATURN', 39 | 'URANUS', 'NEPTUNE', 'PLUTO', 'MEAN NODE', 'TRUE NODE', 'MEAN APOGEE', 'OSC. APOGEE', 40 | 'EARTH', 'CHIRON', 'PHOLUS', 'CERES', 'PALLAS', 'JUNO', 'VESTA', 41 | 'INTP. APOGEE', 'INTP. PERIGEE', 'ASC', 'MC', 'DSC', 'IC', 'DAY PARS', 42 | 'NIGHT PARS', 'SOUTH NODE', 'MARRIAGE PARS', 'BLACK SUN', 'VULCANUS', 'PERSEPHONE', 43 | 'TRUE LILITH'] 44 | 45 | ASPECT_DEGREE = [0, 30, 45, 60, 72, 90, 120, 135, 144, 150, 180] 46 | ASPECT_NAME = ['conjunction', 'semisextile', 'semisquare', 'sextile', 'quintile', 'square', 'trine', 'sesquiquadrate', 47 | 'biquintile', 'quincunx', 'opposition'] 48 | 49 | CONJUNCTION = 0 50 | SEMISEXTILE = 1 51 | SEMISQUARE = 2 52 | SEXTILE = 3 53 | QUINTILE = 4 54 | SQUARE = 5 55 | TRINE = 6 56 | SESQUIQUADRATE = 7 57 | BIQUINTILE = 8 58 | QUINCUNX = 9 59 | OPPOSITION = 10 60 | -------------------------------------------------------------------------------- /notebooks/settings.py: -------------------------------------------------------------------------------- 1 | import os 2 | import datetime 3 | import multiprocessing 4 | 5 | from pyastrotrader.constants import * 6 | 7 | NATAL_DATES = { 8 | 'PETR4.SA' : '1953-10-03T19:05:00-03:00', 9 | 'VALE3.SA' : '1997-05-06T17:47:00-03:00', 10 | 'ITUB4.SA' : '2008-11-04T10:00:00-03:00', 11 | 'BBDC4.SA' : '1943-03-10T10:00:00-03:00', 12 | 'ABEV3.SA' : '1999-07-01T10:00:00-03:00', 13 | '^BVSP' : '1968-01-02T10:00:00-03:00' 14 | } 15 | 16 | DATE_MINIMAL_STOCK = { 17 | 'PETR4.SA' : datetime.datetime.strptime('1996-02-01', '%Y-%m-%d') 18 | } 19 | 20 | NPARTITIONS = multiprocessing.cpu_count() * 2 21 | 22 | SWING_TRADE_DURATION = 5 23 | SWING_EXPECTED_VOLATILITY = 3.5 24 | STAGNATION_THRESHOLD = 5 25 | TOP_THRESHOLD = 2 26 | DAYS_TO_PREDICT = 30 27 | 28 | if 'ASSET_TO_CALCULATE' not in os.environ: 29 | raise ValueError("ASSET_TO_CALCULATE was not set...") 30 | 31 | ASSET_TO_CALCULATE = os.environ['ASSET_TO_CALCULATE'] 32 | NATAL_DATE = NATAL_DATES[ASSET_TO_CALCULATE] 33 | DEFAULT_PARAMETERS = './config/default_parameters.json' 34 | DEFAULT_CONFIG = './config/default_config.json' 35 | 36 | SOURCE_FILE = "./input/{}_Daily".format(ASSET_TO_CALCULATE) 37 | 38 | ETA = 0.3 39 | DEPTH = 7 40 | NUM_TREES = 1000 41 | MAX_INTERACTIONS = 50 42 | if os.environ['MODEL'] == 'SWING_TRADE': 43 | MIN_PRECISION = 0.000001 44 | else: 45 | MIN_PRECISION = 0.000001 46 | 47 | param = {} 48 | param['booster'] = 'gbtree' 49 | param['objective'] = 'reg:squarederror' 50 | param['eval_metric'] = 'auc' 51 | param['tree_method'] = 'auto' 52 | param['silent'] = 0 53 | param['subsample'] = 0.5 54 | 55 | PLANETS_TO_CALCULATE = [SUN, MOON, VENUS, MERCURY, MARS, JUPITER, SATURN] 56 | ASPECTS_TO_CALCULATE = [] 57 | 58 | DATE_MINIMAL = datetime.datetime.strptime('1998-01-01', '%Y-%m-%d') 59 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | attrs==19.3.0 2 | backcall==0.1.0 3 | bleach==3.1.0 4 | certifi==2019.11.28 5 | chardet==3.0.4 6 | cloudpickle==1.2.2 7 | cycler==0.10.0 8 | dask==2.10.1 9 | decorator==4.4.1 10 | defusedxml==0.6.0 11 | eli5==0.10.1 12 | entrypoints==0.3 13 | et-xmlfile==1.0.1 14 | fsspec==0.6.2 15 | graphviz==0.13.2 16 | idna==2.8 17 | importlib-metadata==1.2.0 18 | ipykernel==5.1.3 19 | ipython==7.10.1 20 | ipython-genutils==0.2.0 21 | ipywidgets==7.5.1 22 | jdcal==1.4.1 23 | jedi==0.15.1 24 | Jinja2==2.10.3 25 | joblib==0.14.1 26 | json5==0.8.5 27 | jsonschema==3.2.0 28 | jupyter-client==5.3.4 29 | jupyter-core==4.6.1 30 | jupyterlab==1.2.3 31 | jupyterlab-server==1.0.6 32 | kiwisolver==1.1.0 33 | locket==0.2.0 34 | MarkupSafe==1.1.1 35 | matplotlib==3.1.2 36 | mistune==0.8.4 37 | more-itertools==8.0.2 38 | mplfinance==0.11.1a0 39 | nbconvert==5.6.1 40 | nbformat==4.4.0 41 | notebook==6.0.2 42 | numpy==1.17.4 43 | openpyxl==3.0.2 44 | pandas==0.25.3 45 | pandocfilters==1.4.2 46 | parso==0.5.1 47 | partd==1.1.0 48 | pexpect==4.7.0 49 | pickleshare==0.7.5 50 | plotly==4.3.0 51 | prometheus-client==0.7.1 52 | prompt-toolkit==3.0.2 53 | psutil==5.6.7 54 | ptyprocess==0.6.0 55 | pudb==2019.2 56 | Pygments==2.5.2 57 | pyparsing==2.4.6 58 | pyrsistent==0.15.6 59 | pyswisseph==2.0.0.post2 60 | python-dateutil==2.8.1 61 | pytz==2019.3 62 | pyzmq==18.1.1 63 | requests==2.22.0 64 | retrying==1.3.3 65 | ruamel.yaml==0.16.5 66 | ruamel.yaml.clib==0.2.0 67 | scikit-learn==0.22 68 | scipy==1.3.3 69 | Send2Trash==1.5.0 70 | six==1.13.0 71 | sklearn==0.0 72 | tabulate==0.8.6 73 | terminado==0.8.3 74 | testpath==0.4.4 75 | toolz==0.10.0 76 | tornado==6.0.3 77 | traitlets==4.3.3 78 | urllib3==1.25.7 79 | urwid==2.1.0 80 | vext==0.7.3 81 | wcwidth==0.1.7 82 | webencodings==0.5.1 83 | widgetsnbextension==3.5.1 84 | xgboost==0.90 85 | xlrd==1.2.0 86 | xlwt==1.3.0 87 | zipp==0.6.0 88 | -------------------------------------------------------------------------------- /run_notebooks_multiple.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z '$ASSET_TO_CALCULATE' ] 4 | then 5 | echo 'Please set the ASSET_TO_CALCULATE environment variable' 6 | exit -1 7 | fi 8 | 9 | if [ -z '$ALPHAVANTAGE_KEY' ] 10 | then 11 | echo 'Please set the ALPHAVANTAGE_KEY environment variable' 12 | exit -1 13 | fi 14 | 15 | if [ -z '$MODEL' ] 16 | then 17 | echo 'Please set the MODEL environment variable' 18 | exit -1 19 | fi 20 | 21 | #Create a virtualenv if it doesnt exist 22 | if [ ! -d "./env" ]; then 23 | virtualenv -p python3 env 24 | source env/bin/activate 25 | pip install -r requirements.txt 26 | else 27 | source env/bin/activate 28 | fi 29 | 30 | #Load the virtualenv created 31 | 32 | export PYTHONPATH=$PYTHOPATH:$PWD:$PWD/notebooks 33 | export SWISSEPH_PATH=$PWD/pyastrotrader/swisseph 34 | 35 | date > start.txt 36 | 37 | rm -rf ./notebooks/output/* 38 | cd notebooks 39 | 40 | count=0 41 | MAX_INTERACTIONS=50 42 | 43 | 44 | jupyter nbconvert --ExecutePreprocessor.timeout=-1 --execute DownloadData.ipynb 45 | 46 | while [ $count -lt $MAX_INTERACTIONS ] 47 | do 48 | echo "Running:$count" 49 | if [ $MODEL == "PRICE_CHANGE" ] 50 | then 51 | jupyter nbconvert --ExecutePreprocessor.timeout=-1 --execute CreateModel.price.change.ipynb 52 | jupyter nbconvert --ExecutePreprocessor.timeout=-1 --execute Predict.price.change.ipynb 53 | fi 54 | if [ $MODEL == "SWING_TRADE" ] 55 | then 56 | jupyter nbconvert --ExecutePreprocessor.timeout=-1 --execute CreateModel.swing.trade.ipynb 57 | jupyter nbconvert --ExecutePreprocessor.timeout=-1 --execute Predict.swing.trade.ipynb 58 | fi 59 | count=`expr $count + 1` 60 | done 61 | 62 | cd .. 63 | 64 | source ./clean_notebooks.sh 65 | 66 | date > end.txt 67 | -------------------------------------------------------------------------------- /notebooks/config/default_parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "is_visible_sun": "1", 3 | "is_visible_moon": "1", 4 | "is_visible_mercury": "1", 5 | "is_visible_venus": "1", 6 | "is_visible_mars": "1", 7 | "is_visible_jupiter": "1", 8 | "is_visible_saturn": "1", 9 | "is_visible_uranus": "1", 10 | "is_visible_neptune": "1", 11 | "is_visible_pluto": "1", 12 | "is_visible_mean node": "1", 13 | "is_visible_true node": "0", 14 | "is_visible_mean apogee": "0", 15 | "is_visible_osc. apogee": "0", 16 | "is_visible_earth": "0", 17 | "is_visible_chiron": "0", 18 | "is_visible_pholus": "0", 19 | "is_visible_ceres": "0", 20 | "is_visible_pallas": "0", 21 | "is_visible_juno": "0", 22 | "is_visible_vesta": "0", 23 | "is_visible_intp. perigee": "0", 24 | "is_visible_Asc": "0", 25 | "is_visible_Mc": "0", 26 | "is_visible_Dsc": "0", 27 | "is_visible_Ic": "0", 28 | "is_visible_day pars": "0", 29 | "is_visible_night pars": "0", 30 | "is_visible_south node": "0", 31 | "is_visible_marriage pars": "0", 32 | "is_visible_black sun": "0", 33 | "is_visible_vulcanus": "0", 34 | "is_visible_persephone": "0", 35 | "is_visible_true lilith": "0", 36 | "language": "0", 37 | "is_used_aspect_cnj": "1", 38 | "is_used_aspect_opp": "1", 39 | "is_used_aspect_tri": "1", 40 | "is_used_aspect_sqr": "1", 41 | "is_used_aspect_sxt": "1", 42 | "is_used_aspect_ssq": "1", 43 | "is_used_aspect_qnx": "1", 44 | "natal_cnj_separation": "8", 45 | "natal_opp_separation": "8", 46 | "natal_tri_separation": "8", 47 | "natal_sqr_separation": "8", 48 | "natal_sxt_separation": "8", 49 | "natal_ssq_separation": "8", 50 | "natal_qnx_separation": "8", 51 | "natal_cnj_applying": "8", 52 | "natal_opp_applying": "8", 53 | "natal_tri_applying": "8", 54 | "natal_sqr_applying": "8", 55 | "natal_sxt_applying": "8", 56 | "natal_ssq_applying": "8", 57 | "natal_qnx_applying": "8" 58 | } 59 | -------------------------------------------------------------------------------- /pyastrotrader/test/default_parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "is_visible_sun": "1", 3 | "is_visible_moon": "1", 4 | "is_visible_mercury": "1", 5 | "is_visible_venus": "1", 6 | "is_visible_mars": "1", 7 | "is_visible_jupiter": "1", 8 | "is_visible_saturn": "1", 9 | "is_visible_uranus": "1", 10 | "is_visible_neptune": "1", 11 | "is_visible_pluto": "1", 12 | "is_visible_mean node": "1", 13 | "is_visible_true node": "0", 14 | "is_visible_mean apogee": "0", 15 | "is_visible_osc. apogee": "0", 16 | "is_visible_earth": "0", 17 | "is_visible_chiron": "0", 18 | "is_visible_pholus": "0", 19 | "is_visible_ceres": "0", 20 | "is_visible_pallas": "0", 21 | "is_visible_juno": "0", 22 | "is_visible_vesta": "0", 23 | "is_visible_intp. perigee": "0", 24 | "is_visible_Asc": "0", 25 | "is_visible_Mc": "0", 26 | "is_visible_Dsc": "0", 27 | "is_visible_Ic": "0", 28 | "is_visible_day pars": "0", 29 | "is_visible_night pars": "0", 30 | "is_visible_south node": "0", 31 | "is_visible_marriage pars": "0", 32 | "is_visible_black sun": "0", 33 | "is_visible_vulcanus": "0", 34 | "is_visible_persephone": "0", 35 | "is_visible_true lilith": "0", 36 | "language": "0", 37 | "is_used_aspect_cnj": "1", 38 | "is_used_aspect_opp": "1", 39 | "is_used_aspect_tri": "1", 40 | "is_used_aspect_sqr": "1", 41 | "is_used_aspect_sxt": "1", 42 | "is_used_aspect_ssq": "1", 43 | "is_used_aspect_qnx": "1", 44 | "natal_cnj_separation": "8", 45 | "natal_opp_separation": "8", 46 | "natal_tri_separation": "8", 47 | "natal_sqr_separation": "8", 48 | "natal_sxt_separation": "8", 49 | "natal_ssq_separation": "8", 50 | "natal_qnx_separation": "8", 51 | "natal_cnj_applying": "8", 52 | "natal_opp_applying": "8", 53 | "natal_tri_applying": "8", 54 | "natal_sqr_applying": "8", 55 | "natal_sxt_applying": "8", 56 | "natal_ssq_applying": "8", 57 | "natal_qnx_applying": "8" 58 | } 59 | -------------------------------------------------------------------------------- /pyastrotrader/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import swisseph as swe 4 | 5 | def check_key_exists(json_dict, key, key2=None): 6 | if key not in json_dict: 7 | return None 8 | else: 9 | if key2 is None: 10 | return json_dict[key] 11 | else: 12 | if key2 in json_dict[key]: 13 | return json_dict[key][key2] 14 | else: 15 | return json_dict 16 | 17 | 18 | def check_json(json_parsed): 19 | for key in [('config', 'postype'), ('config', 'zodiactype'), 20 | ('config', 'house_system'), ('chart', 'longitude'), 21 | ('chart', 'date'), ('chart', 'latitude'), ('chart', 22 | 'altitude')]: 23 | if check_key_exists(json_parsed, key[0], key[1]) is None: 24 | raise ValueError("Key:{}/{} is expected in json".format( 25 | key[0], key[1])) 26 | 27 | 28 | def check_input(input_json): 29 | try: 30 | if 'SWISSEPH_PATH' in os.environ: 31 | ephe_path = os.environ['SWISSEPH_PATH'] 32 | else: 33 | raise ValueError("SWISSEPH_PATH must be set....") 34 | 35 | if os.path.isdir(ephe_path): 36 | swe.set_ephe_path(ephe_path) 37 | else: 38 | raise ValueError("Error, swiss ephemeris was not found") 39 | 40 | check_json(input_json) 41 | 42 | return input_json 43 | except Exception as e: 44 | raise ValueError(str(e)) 45 | 46 | def check_key_exists(json_dict, key, key2=None): 47 | if key not in json_dict: 48 | return None 49 | else: 50 | if key2 is None: 51 | return json_dict[key] 52 | else: 53 | if key2 in json_dict[key]: 54 | return json_dict[key][key2] 55 | else: 56 | return json_dict 57 | 58 | 59 | def check_json(json_parsed): 60 | for key in [('config', 'postype'), ('config', 'zodiactype'), 61 | ('config', 'house_system'), ('chart', 'longitude'), 62 | ('chart', 'date'), ('chart', 'latitude'), ('chart', 63 | 'altitude')]: 64 | if check_key_exists(json_parsed, key[0], key[1]) is None: 65 | raise ValueError("Key:{}/{} is expected in json".format( 66 | key[0], key[1])) 67 | 68 | 69 | def check_input(input_json): 70 | try: 71 | if 'SWISSEPH_PATH' in os.environ: 72 | ephe_path = os.environ['SWISSEPH_PATH'] 73 | else: 74 | raise ValueError("SWISSEPH_PATH must be set....") 75 | 76 | if os.path.isdir(ephe_path): 77 | swe.set_ephe_path(ephe_path) 78 | else: 79 | raise ValueError("Error, swiss ephemeris was not found") 80 | 81 | check_json(input_json) 82 | 83 | return input_json 84 | except Exception as e: 85 | raise ValueError(str(e)) 86 | 87 | -------------------------------------------------------------------------------- /pyastrotrader/transits/transits.py: -------------------------------------------------------------------------------- 1 | from ..constants import * 2 | 3 | 4 | def already_added(found_aspects, c_planet, n_planet, c_aspect): 5 | search = [x for x in found_aspects if 6 | (x['c_aspect'] == c_aspect and x['c_planet'] == c_planet and x['n_planet'] == n_planet) or ( 7 | x['c_aspect'] == c_aspect and x['c_planet'] == n_planet and x['n_planet'] == c_planet)] 8 | return len(search) > 0 9 | 10 | 11 | def get_degrees(chart, planetA, planetB): 12 | c_planet_degreeA = chart['planets']['planets_degree_ut'][planetA] 13 | c_planet_degreeB = chart['planets']['planets_degree_ut'][planetB] 14 | return c_planet_degreeA - c_planet_degreeB 15 | 16 | def calculate_aspects(chart, planets, transits, tolerance): 17 | found_aspects = [] 18 | 19 | for c_aspect in transits: 20 | c_aspect_angle = ASPECT_DEGREE[c_aspect] 21 | for c_planet in planets: 22 | c_planet_degree = chart['planets']['planets_degree_ut'][c_planet] 23 | for n_planet in planets: 24 | if c_planet == n_planet: 25 | continue 26 | n_planet_degree = chart['planets']['planets_degree_ut'][n_planet] 27 | current_separation = abs(n_planet_degree - c_planet_degree) 28 | current_tolerance = abs(current_separation - c_aspect_angle) 29 | if abs(current_tolerance) < tolerance: 30 | if not already_added(found_aspects, c_planet, n_planet, c_aspect): 31 | found_aspects.append({ 32 | "c_aspect_name": ASPECT_NAME[c_aspect], 33 | "n_planet_name": PLANETS[n_planet], 34 | "c_planet_name": PLANETS[c_planet], 35 | "c_planet": c_planet, 36 | "c_planet_degree": c_planet_degree, 37 | "n_planet": n_planet, 38 | "n_planet_degree": n_planet_degree, 39 | "c_aspect": c_aspect, 40 | "c_aspect_angle": c_aspect_angle, 41 | "c_aspect_separation": current_separation}) 42 | 43 | return found_aspects 44 | 45 | 46 | def calculate_transits(radix_chart, transiting_chart, planets, transits, tolerance): 47 | found_transits = [] 48 | 49 | for c_aspect in transits: 50 | c_aspect_angle = ASPECT_DEGREE[c_aspect] 51 | for c_planet in planets: 52 | c_planet_degree = radix_chart['planets']['planets_degree_ut'][c_planet] 53 | for n_planet in planets: 54 | n_planet_degree = transiting_chart['planets']['planets_degree_ut'][n_planet] 55 | current_separation = abs(n_planet_degree - c_planet_degree) 56 | current_tolerance = abs(current_separation - c_aspect_angle) 57 | if abs(current_tolerance) < tolerance: 58 | if not already_added(found_transits, c_planet, n_planet, c_aspect): 59 | found_transits.append({ 60 | "c_aspect_name": ASPECT_NAME[c_aspect], 61 | "n_planet_name": PLANETS[n_planet], 62 | "c_planet_name": PLANETS[c_planet], 63 | "c_planet": c_planet, 64 | "c_planet_degree": c_planet_degree, 65 | "n_planet": n_planet, 66 | "n_planet_degree": n_planet_degree, 67 | "c_aspect": c_aspect, 68 | "c_aspect_angle": c_aspect_angle, 69 | "c_aspect_separation": current_separation}) 70 | 71 | return found_transits 72 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AstroTrader 2 | 3 | AstroTrader is a project to investigate the correlation between Astrological events and the price fluctuations in the stock market as Trends, this is a research project and it is not meant to be used in the real market. 4 | 5 | Although Financial Markets and Astrology seems to be totally unrelated subjects, the fact is that many of the great bankers and traders of the last 200 years, took astrology seriously on its capability to predict medium and long-term trends in the Financial Market 6 | 7 | ![](docs/jpmorgan.jpg) 8 | 9 | The subject of financial astrology has been well research for the last 70 years, and I recommend the following books on the subject: 10 | 11 | * [Financial-Astrology, David-Williams](https://www.amazon.com/Financial-Astrology-David-Williams/dp/0866900454) 12 | * [The Bull, The Bear and The Planets: Trading the Financial Markets Using Astrology](https://www.amazon.com/Exploring-Financial-Universe-Planets-Finance/dp/0892542187/ref=pd_sbs_14_t_1/145-5392391-6321207) 13 | * [Exploring the Financial Universe: The Role of the Sun and Planets in the World of Finance](https://www.amazon.com/Exploring-Financial-Universe-Planets-Finance/dp/0892542187/ref=pd_sbs_14_t_1/145-5392391-6321207) 14 | 15 | ## Why Astrology? 16 | 17 | Nature on planet earth uses the movement of the planets around itself, in order to mark the seasons and its biological and geological cycles. The study of the relation between the movement of the planets and such cycles is called Astrology. 18 | 19 | Astrology is mankind`s first science, and its research allowed us to leave the hunter-gatherer societies and evolve to large, complex, agricultural-based ones. As the ancient civilizations were able to predict the best time to sow and to rip its harvests, it allowed agriculture to be a safer activity than hunting and/or gathering fruits. 20 | 21 | The first uses of Math and Written language were to record both the stocks of granaries and also the movement of the planets on the Sky. Great Megalithic structures like Stonehenge and the Ziggurats of Sumer were primarily used as astrological observatories. 22 | 23 | ## Astrology and Financial Markets 24 | 25 | It is well known that Astrology was one of the enablers of the Agricultural Revolution, about 5k-6k years ago, but what is its relation to the stock market? *As all Nature on Earth is influenced by the position of the planets on the sky, the human psychology is also subconsciously influenced by such movements as well.* 26 | 27 | It is a well know fact that crime rates sour during the Full Moon and decrease during the New Moon, that certain planet alignments also have influence on pregnancy rates, because we are part of Nature and we also use the movement of the planets around us to measure biological cycles. 28 | 29 | So, what causes the prices fluctuation on the stock market? 30 | 31 | **The prices on the stock market are merely a projection of the risk perception of a certain asset** 32 | 33 | So, as any trader knows, the price on the market is 100% determined by psychological perception of Fear or Greed. And the objective of this project is to measure and determine the influence of the movement of the planets on the perception of risk for a certain Asset traded in a Stock Exchange. 34 | 35 | ## Install and Usage 36 | 37 | The Software consists of python jupyter notebooks that download data from a public stock quotes API, creates a machine learning model, and then runs predictions for the future on the probabilities of price increase and decrease for the certain commodity. 38 | 39 | It is required the following software: 40 | 41 | * Linux OS (Have tested with Arch and Ubuntu Distributions) 42 | * Python 3.6 installed globally. 43 | 44 | It is necessary to obtain a public token from Alphavantage in order to retrieve the quotes for the assets, this key is free and can be obtained here: 45 | 46 | [https://www.alphavantage.co/support/#api-key](https://www.alphavantage.co/support/#api-key) 47 | 48 | In order to use the software, it is necessary to clone this repository, and run the following scripts: 49 | 50 | set ASSET_TO_CALCULATE=<> 51 | set ALPHAVANTAGE_KEY=<> 52 | 53 | mkdir notebooks/input 54 | mkdir notebooks/output 55 | ./start_notebooks.sh 56 | 57 | The start_notebooks script will create the python environment, install the necessary modules and then start the jupyter lab server. The startup procedure will print on the terminal screen, a URL that can be accessed using any browser in order to access the notebooks. 58 | 59 | If there is no need to access the notebooks, they can be run directly on the CLI: 60 | 61 | set ASSET_TO_CALCULATE=<> 62 | set ALPHAVANTAGE_KEY=<> 63 | 64 | mkdir notebooks/input 65 | mkdir notebooks/output 66 | ./run_notebooks.sh 67 | 68 | The script above will run the entire process and save in notebooks/output the results of the computations. 69 | 70 | ## Software Architecture 71 | 72 | The project is developed using Jupyter Notebooks, which allow for a very fast development and also a very intuitive analysis of the data being processed by the python notebook. 73 | 74 | It also contains a module: ```pyastrotrader``` that provides astrological computations using the ```swiss ephemeris```. 75 | 76 | The project contains 3 main notebooks: 77 | 78 | * **DownloadData.ipynb**: This notebook downloads the stock quotes of the last 20 years, for the asset specified in the environment variable: ```ASSET_TO_CALCULATE```, and saves the quotes as a CSV file in the ```notebooks/input``` folder 79 | * **CreateModel.ipynb**: This notebooks creates a pandas dataframe with the downloaded quotes for the specified asset in ```ASSET_TO_CALCULATE```, calculates the astrological positions of the planets for each day, and then run a XGBoost training algorithm in order to detect the correlation between each astrological aspect and the price trend for the next 5 days. The model then is saved in the ```notebooks/output``` folder. 80 | * **Predict.ipynb**: This notebook loads the model created in the previous notebook and then runs prediction of the price trend for the next 180 days, storing the results in the ```notebooks/output``` folder. 81 | 82 | Inside each notebook there are explanations for the algorithms being used, please start the jupyter lab server and then navigate the notebooks in order to examine in details its architecture and design. 83 | 84 | -------------------------------------------------------------------------------- /pyastrotrader/calculate/calculate.py: -------------------------------------------------------------------------------- 1 | import dateutil.parser 2 | import swisseph as swe 3 | 4 | SEFLG_JPLEPH = 1 5 | SEFLG_SWIEPH = 2 6 | SEFLG_MOSEPH = 4 7 | SEFLG_HELCTR = 8 8 | SEFLG_TRUEPOS = 16 9 | SEFLG_J2000 = 32 10 | SEFLG_NONUT = 64 11 | SEFLG_SPEED3 = 128 12 | SEFLG_SPEED = 256 13 | SEFLG_NOGDEF = 512 14 | SEFLG_NOABERR = 1024 15 | SEFLG_EQUATORIAL = 2048 16 | SEFLG_XYZ = 4096 17 | SEFLG_RADIANS = 8192 18 | SEFLG_BARYCTR = 16384 19 | SEFLG_TOPOCTR = (32 * 1024) 20 | SEFLG_SIDEREAL = (64 * 1024) 21 | 22 | NUM_PLANETS = 23 23 | 24 | 25 | def calculate_house(planet_degree, houses): 26 | distance = [(i, x - planet_degree, abs(x - planet_degree)) 27 | for i, x in enumerate(houses) if (x - planet_degree) < 0] 28 | distance_sorted = sorted(distance, key=lambda x: x[2]) 29 | if len(distance_sorted) > 0: 30 | distance_sorted = distance_sorted[0] 31 | ret = "{}:{}:{}".format(distance_sorted[0], distance_sorted[2], 32 | 'sep' if distance_sorted[1] > 0 else 'app') 33 | else: 34 | ret = "0:0:0" 35 | return ret 36 | 37 | 38 | def calculate_planets_in_houses(chart): 39 | degrees_planets = chart['planets']['planets_degree_ut'] 40 | houses_planets = [0] * 23 41 | for i in range(NUM_PLANETS): 42 | planet_degree = degrees_planets[i] 43 | houses_planets[i] = calculate_house(planet_degree, 44 | chart['houses']['sh'][0]) 45 | chart['planets']['planets_houses'] = houses_planets 46 | return chart 47 | 48 | 49 | def calculate_main_chart(input_data, intermediate, output): 50 | output['houses'] = {} 51 | output['houses']['sh'] = {} 52 | output['houses']['sh'] = swe.houses( 53 | intermediate['jul_day_UT'], float(input_data['chart']['latitude']), 54 | float(input_data['chart']['longitude']), 55 | input_data['config']['house_system'].encode('ascii')) 56 | output['houses']['houses_degree_ut'] = output['houses']['sh'][0] 57 | output['houses']['ps'] = swe.nod_aps_ut( 58 | intermediate['jul_day_UT'], 0, swe.NODBIT_MEAN, intermediate['iflag']) 59 | output['houses']['pl'] = swe.nod_aps_ut( 60 | intermediate['jul_day_UT'], 1, swe.NODBIT_MEAN, intermediate['iflag']) 61 | 62 | return output 63 | 64 | def get_degree(chart, planet): 65 | return chart['planets']['planets_degree_ut'][planet] 66 | 67 | def calculate_planets(input_data, intermediate, output, config): 68 | output['planets'] = {} 69 | output['planets']['planets_sign_name'] = [0] * 23 70 | output['planets']['planets_degree'] = [0] * 23 71 | output['planets']['planets_degree_ut'] = [0] * 23 72 | output['planets']['planets_retrograde'] = [0] * 23 73 | 74 | for i in range(NUM_PLANETS): 75 | ret_flag = swe.calc_ut(intermediate['jul_day_UT'], i, 76 | intermediate['iflag']) 77 | for x in range(len(config['zodiac'])): 78 | deg_low = float(x * 30) 79 | deg_high = float((x + 1) * 30) 80 | if ret_flag[0] >= deg_low: 81 | if ret_flag[0] <= deg_high: 82 | output['planets']['planets_sign_name'][ 83 | i] = config['planet_name_short'][i] + ":" + config[ 84 | 'zodiac'][x] + ":" + str(x) 85 | output['planets']['planets_degree'][ 86 | i] = ret_flag[0] - deg_low 87 | output['planets']['planets_degree_ut'][i] = ret_flag[0] 88 | if ret_flag[3] < 0: 89 | output['planets']['planets_retrograde'][i] = True 90 | else: 91 | output['planets']['planets_retrograde'][i] = False 92 | return output 93 | 94 | 95 | def calculate_iflag(input_data): 96 | 97 | config = input_data['config'] 98 | 99 | iflag = SEFLG_SWIEPH + SEFLG_SPEED 100 | 101 | if config['postype'] == 'truegeo': 102 | iflag += SEFLG_TRUEPOS 103 | if config['postype'] == 'topo': 104 | iflag += SEFLG_TOPOCTR 105 | if config['postype'] == 'helio': 106 | iflag += SEFLG_HELCTR 107 | 108 | if config['zodiactype'] == 'sidereal': 109 | iflag += SEFLG_SIDEREAL 110 | swe.set_sid_mode(getattr(swe, 'SIDM_' + config['siderealmode'])) 111 | 112 | return iflag 113 | 114 | 115 | def compute_hour(input_time): 116 | return input_time.hour + (input_time.minute / 60) + ( 117 | input_time.second / 3600) 118 | 119 | 120 | def generate_chart(config, input_data): 121 | input_time = dateutil.parser.parse(input_data["chart"]['date']) 122 | 123 | intermediate = {} 124 | intermediate['jul_day_UT'] = swe.julday(input_time.year, input_time.month, 125 | input_time.day, 126 | compute_hour(input_time)) 127 | 128 | intermediate['geo_loc'] = swe.set_topo( 129 | float(input_data['chart']['longitude']), 130 | float(input_data['chart']['latitude']), 131 | float(input_data['chart']['altitude'])) 132 | 133 | intermediate['iflag'] = calculate_iflag(input_data) 134 | 135 | output = {} 136 | output['input'] = input_data 137 | output['intermediate'] = intermediate 138 | output = calculate_planets(input_data, intermediate, output, config) 139 | output = calculate_main_chart(input_data, intermediate, output) 140 | output = calculate_planets_in_houses(output) 141 | return output 142 | 143 | 144 | def load_config(input_data): 145 | config = {} 146 | config['zodiac'] = [ 147 | 'aries', 'taurus', 'gemini', 'cancer', 'leo', 'virgo', 'libra', 148 | 'scorpio', 'sagittarius', 'capricorn', 'aquarius', 'pisces' 149 | ] 150 | config['planet_name_short'] = [ 151 | 'sun', 'moon', 'mercury', 'venus', 'mars', 'jupiter', 'saturn', 152 | 'uranus', 'neptune', 'pluto', 'Node', '?', 'Lilith', '?', 'earth', 153 | 'chiron', 'pholus', 'ceres', 'pallas', 'juno', 'vesta', 'intp. apogee', 154 | 'intp. perigee', 'Asc', 'Mc', 'Dsc', 'Ic', 'DP', 'NP', 'SNode', 155 | 'marriage', 'blacksun', 'vulcanus', 'persephone', 'truelilith' 156 | ] 157 | 158 | config["postype"] = input_data['config']['postype'] 159 | config["zodiactype"] = input_data['config']['zodiactype'] 160 | config["house_system"] = input_data['config']['house_system'] 161 | 162 | return config 163 | -------------------------------------------------------------------------------- /notebooks/DownloadData.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# pyAstroTrader\n", 8 | "\n", 9 | "## Download Data\n", 10 | "\n", 11 | "This notebook contains the code to download the quotes from the ALPHAVANTAGE API for the asset indicated in the environment key: ASSET_TO_CALCULATE\n", 12 | "\n", 13 | "The first step is to import all settings and also python modules that we are going to use." 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": null, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "import os\n", 23 | "import datetime\n", 24 | "import pandas as pd\n", 25 | "import numpy as np\n", 26 | "import requests\n", 27 | "\n", 28 | "from IPython.display import display, HTML\n", 29 | "\n", 30 | "from settings import *" 31 | ] 32 | }, 33 | { 34 | "cell_type": "markdown", 35 | "metadata": {}, 36 | "source": [ 37 | "After all settings have been imported, we can check if the API key is correctly set in the environment variables of the process, and then use it to retrieve the quotes as a JSON file." 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": null, 43 | "metadata": {}, 44 | "outputs": [], 45 | "source": [ 46 | "if 'ALPHAVANTAGE_KEY' not in os.environ:\n", 47 | " raise ValueError('Need to define the API_KEY for the quotes')\n", 48 | " \n", 49 | "ALPHAVANTAGE_KEY = os.environ['ALPHAVANTAGE_KEY']\n", 50 | "URL='https://www.alphavantage.co/query?function=TIME_SERIES_DAILY_ADJUSTED&symbol={}&outputsize=full&apikey={}'.format(ASSET_TO_CALCULATE,ALPHAVANTAGE_KEY)\n", 51 | "\n", 52 | "response = requests.get(URL)\n", 53 | "if response.status_code != 200:\n", 54 | " raise ValueError('Error in getting the Data')\n", 55 | " \n", 56 | "response = response.json()" 57 | ] 58 | }, 59 | { 60 | "cell_type": "markdown", 61 | "metadata": {}, 62 | "source": [ 63 | "After we receive the json file we need to retrieve the days that we need to process" 64 | ] 65 | }, 66 | { 67 | "cell_type": "code", 68 | "execution_count": null, 69 | "metadata": {}, 70 | "outputs": [], 71 | "source": [ 72 | "data_to_process = response['Time Series (Daily)']\n", 73 | "days = list(data_to_process.keys())" 74 | ] 75 | }, 76 | { 77 | "cell_type": "markdown", 78 | "metadata": {}, 79 | "source": [ 80 | "With the days, we can now iterate over them and generate a list of dictionaries with the correct column name for the pandas dataframe to be used in our processing" 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "execution_count": null, 86 | "metadata": {}, 87 | "outputs": [], 88 | "source": [ 89 | "data_for_pandas = []\n", 90 | "for current_day in days:\n", 91 | " current_day_date = datetime.datetime.strptime(current_day, '%Y-%m-%d')\n", 92 | " if current_day_date < DATE_MINIMAL:\n", 93 | " continue\n", 94 | " if ASSET_TO_CALCULATE in DATE_MINIMAL_STOCK:\n", 95 | " if current_day_date < DATE_MINIMAL_STOCK[ASSET_TO_CALCULATE]:\n", 96 | " continue\n", 97 | " \n", 98 | " if float(data_to_process[current_day]['4. close']) == 0:\n", 99 | " continue\n", 100 | " \n", 101 | " data_for_pandas.append(\n", 102 | " {\n", 103 | " 'Date': current_day.replace('-',''),\n", 104 | " 'Price': float(data_to_process[current_day]['4. close']),\n", 105 | " 'Open': float(data_to_process[current_day]['1. open']),\n", 106 | " 'High': float(data_to_process[current_day]['2. high']),\n", 107 | " 'Low': float(data_to_process[current_day]['3. low']),\n", 108 | " 'Vol': float(data_to_process[current_day]['6. volume'])\n", 109 | " }\n", 110 | " )\n", 111 | "data_for_pandas = sorted(data_for_pandas, key=lambda x: x['Date'], reverse=False)" 112 | ] 113 | }, 114 | { 115 | "cell_type": "markdown", 116 | "metadata": {}, 117 | "source": [ 118 | "With the list of dictionaries, we can then create the pandas dataframe with the quotes data, using the constructor that takes as parameter the list of dictionaries" 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": null, 124 | "metadata": {}, 125 | "outputs": [], 126 | "source": [ 127 | "df = pd.DataFrame(data_for_pandas)" 128 | ] 129 | }, 130 | { 131 | "cell_type": "markdown", 132 | "metadata": {}, 133 | "source": [ 134 | "We need to generate the CSV file that will be consumed by the ```CreateModel.ipynb``` notebook, we can use pandas builtin dataframe method to do it..." 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": null, 140 | "metadata": {}, 141 | "outputs": [], 142 | "source": [ 143 | "output_csv_file='./input/{}_Daily.csv'.format(ASSET_TO_CALCULATE)\n", 144 | "df.to_csv(output_csv_file)" 145 | ] 146 | }, 147 | { 148 | "cell_type": "markdown", 149 | "metadata": {}, 150 | "source": [ 151 | "And we use the excel method to generate a excel workbook with the quotes data..." 152 | ] 153 | }, 154 | { 155 | "cell_type": "code", 156 | "execution_count": null, 157 | "metadata": {}, 158 | "outputs": [], 159 | "source": [ 160 | "output_excel_file='./input/{}_Daily.xlsx'.format(ASSET_TO_CALCULATE)\n", 161 | "df.to_excel(output_excel_file)" 162 | ] 163 | }, 164 | { 165 | "cell_type": "code", 166 | "execution_count": null, 167 | "metadata": {}, 168 | "outputs": [], 169 | "source": [] 170 | }, 171 | { 172 | "cell_type": "code", 173 | "execution_count": null, 174 | "metadata": {}, 175 | "outputs": [], 176 | "source": [] 177 | } 178 | ], 179 | "metadata": { 180 | "kernelspec": { 181 | "display_name": "Python 3", 182 | "language": "python", 183 | "name": "python3" 184 | }, 185 | "language_info": { 186 | "codemirror_mode": { 187 | "name": "ipython", 188 | "version": 3 189 | }, 190 | "file_extension": ".py", 191 | "mimetype": "text/x-python", 192 | "name": "python", 193 | "nbconvert_exporter": "python", 194 | "pygments_lexer": "ipython3", 195 | "version": "3.8.1" 196 | } 197 | }, 198 | "nbformat": 4, 199 | "nbformat_minor": 4 200 | } 201 | -------------------------------------------------------------------------------- /notebooks/helpers.py: -------------------------------------------------------------------------------- 1 | import os 2 | import gc 3 | 4 | import pandas as pd 5 | import numpy as np 6 | 7 | from sklearn.model_selection import KFold 8 | from sklearn.model_selection import train_test_split as ttsplit 9 | from sklearn.metrics import mean_squared_error as mse 10 | 11 | import xgboost as xgb 12 | from xgboost import XGBClassifier 13 | from xgboost import plot_importance 14 | from xgboost import plot_tree 15 | 16 | 17 | from pyastrotrader.constants import * 18 | from pyastrotrader import get_degrees, get_degree 19 | from settings import * 20 | 21 | charts = {} 22 | aspects = {} 23 | aspects_transiting = {} 24 | 25 | def correct_date(x): 26 | date_str = str(x['Date']) 27 | return date_str[0:4] + '-' + date_str[4:6] + '-' + date_str[6:8] 28 | 29 | def change_sign(x,y): 30 | return not ((x > 0 and y > 0) or (x < 0 and y < 0)) 31 | 32 | def get_previous_stock_price(df, x, swing_trade_duration): 33 | if x['Counter'] > (swing_trade_duration - 1): 34 | return float(df[df['Counter'] == (x['Counter'] - swing_trade_duration)]['Price']) 35 | else: 36 | return 0 37 | 38 | def get_future_stock_price(df, x, max, swing_trade_duration): 39 | if x['Counter'] < (max - swing_trade_duration): 40 | return float(df[df['Counter'] == (x['Counter'] + swing_trade_duration)]['Price']) 41 | else: 42 | return 0 43 | 44 | def get_future_stock_max_price(df, x, max, swing_trade_duration): 45 | if x['Counter'] < (max): 46 | current_range = df[df['Counter'] <= (x['Counter'] + swing_trade_duration)] 47 | current_range = current_range[current_range['Counter'] > x['Counter']] 48 | return current_range['High'].max() 49 | else: 50 | return 0 51 | 52 | def get_future_stock_min_price(df, x, max, swing_trade_duration): 53 | if x['Counter'] < (max): 54 | current_range = df[df['Counter'] <= (x['Counter'] + swing_trade_duration)] 55 | current_range = current_range[current_range['Counter'] > x['Counter']] 56 | return current_range['High'].min() 57 | else: 58 | return 0 59 | 60 | def calculate_current_trend(x): 61 | if x['PreviousStartPrice'] > 0.0: 62 | return ((float(x['Price']) / float(x['PreviousStartPrice'])) - 1) * 100 63 | else: 64 | return 0; 65 | 66 | def get_previous_stock_date(df, x, swing_trade_duration): 67 | if x['Counter'] > (swing_trade_duration - 1): 68 | return float(df[df['Counter'] == (x['Counter'] - swing_trade_duration)]['Date']) 69 | else: 70 | return 0 71 | 72 | def get_future_stock_date(df, x, max, swing_trade_duration): 73 | if x['Counter'] < (max - swing_trade_duration): 74 | return float(df[df['Counter'] == (x['Counter'] + swing_trade_duration)]['Date']) 75 | else: 76 | return 0 77 | 78 | def calculate_future_trend(x): 79 | if x['FutureFinalPrice'] > 0: 80 | return ((float(x['FutureFinalPrice']) / float(x['Price'])) - 1) * 100 81 | else: 82 | return 0; 83 | 84 | def calculate_intraday_volatility(df, x, swing_trade_duration): 85 | current_range = df[df['Counter'] >= (x['Counter'] - (swing_trade_duration * 2))] 86 | current_range = current_range[current_range['Counter'] < x['Counter']] 87 | return (((current_range['High'] / current_range['Low']) - 1).sum() / (swing_trade_duration * 2)) * 100 88 | 89 | def calculate_swing_strenght(x): 90 | if float(x['CurrentTrend']) != 0 and float(x['FutureTrend'] != 0): 91 | return abs(float(x['CurrentTrend']) - float(x['FutureTrend'])) 92 | else: 93 | return 0 94 | 95 | def detect_swing_trade(x, swing_expected_volatility): 96 | return 1 if change_sign(x['FutureTrend'], x['CurrentTrend']) and \ 97 | x['SwingStrength'] > (x['IntradayVolatility'] * swing_expected_volatility) and \ 98 | abs(x['FutureTrend']) >= abs(x['CurrentTrend']) else 0 99 | 100 | def detect_swing_trade_bottom(x, df , swing_trade_duration, max): 101 | if x['Counter'] < (max - swing_trade_duration) and \ 102 | x['Counter'] > (swing_trade_duration - 1): 103 | 104 | min_counter = x['Counter'] - swing_trade_duration 105 | max_counter = x['Counter'] + swing_trade_duration 106 | 107 | current_frame = df 108 | current_frame = current_frame[current_frame['Counter'] >= min_counter] 109 | current_frame = current_frame[current_frame['Counter'] <= max_counter] 110 | 111 | return 1 if current_frame['Low'].min() == x['Low'] else 0 112 | else: 113 | return 0 114 | 115 | 116 | def clean_swing_trade(df, x, swing_trade_duration): 117 | if x['IsSwing'] == 1: 118 | current_range = df[df['Counter'] <= (x['Counter'] + swing_trade_duration)] 119 | current_range = current_range[current_range['Counter'] > x['Counter']] 120 | if current_range['IsSwing'].sum() > 0: 121 | return 0 122 | else: 123 | return 1 124 | else: 125 | return 0 126 | 127 | def detect_price_increase(x, stagnation_threshold): 128 | return min(stagnation_threshold * TOP_THRESHOLD, (((x['FutureTrendMax'] / x['Open']) - 1)) * 100) \ 129 | if x['FutureTrendMax'] > x['Open'] and x['FutureTrendMax'] > 0 else 0 130 | 131 | def clean_price_increase(df, x, swing_trade_duration): 132 | if x['StockIncreasedPrice'] == 1: 133 | current_range = df[df['Counter'] >= (x['Counter'] - swing_trade_duration)] 134 | current_range = current_range[current_range['Counter'] < x['Counter']] 135 | if current_range['StockIncreasedPrice'].sum() > 0: 136 | return 0 137 | else: 138 | return 1 139 | else: 140 | return 0 141 | 142 | def detect_price_decrease(x, stagnation_threshold): 143 | return min(stagnation_threshold * TOP_THRESHOLD, (((x['Open'] / x['FutureTrendMin']) - 1)) * 100) \ 144 | if x['FutureTrendMin'] <= x['Open'] and x['FutureTrendMin'] > 0 else 0 145 | 146 | def clean_price_decrease(df, x, swing_trade_duration): 147 | if x['StockDecreasedPrice'] == 1: 148 | current_range = df[df['Counter'] >= (x['Counter'] - swing_trade_duration)] 149 | current_range = current_range[current_range['Counter'] < x['Counter']] 150 | if current_range['StockDecreasedPrice'].sum() > 0: 151 | return 0 152 | else: 153 | return 1 154 | else: 155 | return 0 156 | 157 | def detect_price_stagnated(x, stagnation_threshold): 158 | return 0 if detect_price_increase(x, stagnation_threshold) > stagnation_threshold or \ 159 | detect_price_decrease(x, stagnation_threshold) > stagnation_threshold else 1 160 | 161 | def clean_price_stagnated(df, x, swing_trade_duration): 162 | if x['StockStagnated'] == 1: 163 | current_range = df[df['Counter'] <= (x['Counter'] + swing_trade_duration)] 164 | current_range = current_range[current_range['Counter'] > x['Counter']] 165 | if current_range['StockStagnated'].sum() > 0: 166 | return 0 167 | else: 168 | return 1 169 | else: 170 | return 0 171 | 172 | def is_aspected(row, first_planet, second_planet, aspect): 173 | c_transits = aspects[row['CorrectedDate']] 174 | found_params = [x for x in c_transits if (x['c_planet'] == first_planet and x['n_planet'] == second_planet and x['c_aspect'] == aspect) or \ 175 | (x['n_planet'] == first_planet and x['c_planet'] == second_planet and x['c_aspect'] == aspect) ] 176 | return 1 if len(found_params) > 0 else 0 177 | 178 | def is_aspected_transiting(row, first_planet, second_planet, aspect): 179 | c_transits = aspects_transiting[row['CorrectedDate']] 180 | found_params = [x for x in c_transits if (x['c_planet'] == first_planet and x['n_planet'] == second_planet and x['c_aspect'] == aspect) or \ 181 | (x['n_planet'] == first_planet and x['c_planet'] == second_planet and x['c_aspect'] == aspect) ] 182 | return 1 if len(found_params) > 0 else 0 183 | 184 | 185 | def is_retrograde(row, planet): 186 | if planet in [SUN,MOON]: 187 | return 0 188 | c_chart = charts[row['CorrectedDate']] 189 | return 1 if c_chart['planets']['planets_retrograde'][planet] else 0 190 | 191 | 192 | def get_degrees_for_planets(row, first_planet, second_planet): 193 | c_chart = charts[row['CorrectedDate']] 194 | return abs(get_degrees(c_chart, first_planet, second_planet)) 195 | 196 | def get_degree_for_planet(row, planet): 197 | c_chart = charts[row['CorrectedDate']] 198 | return get_degree(c_chart, planet) 199 | 200 | def calculate_price_change(df, row): 201 | if row['Counter'] > 1: 202 | if ((float(row['Price']) / float(df[df['Counter'] == row['Counter'] -1]['Price'])) - 1) * 100 > 1: 203 | return 1 204 | else: 205 | if ((float(row['Price']) / float(df[df['Counter'] == row['Counter'] -1]['Price'])) - 1) * 100 < -1: 206 | return -1 207 | return 0 208 | 209 | def create_booster_swing_trade(eta,depth,num_trees, train_x, train_y, test_x, test_y, columns, trained_model): 210 | param['max_depth'] = depth 211 | param['eta'] = eta 212 | num_round = num_trees 213 | dtrain = xgb.DMatrix(train_x, train_y, feature_names = columns) 214 | dtest = xgb.DMatrix(test_x, test_y, feature_names = columns) 215 | train_labels = dtrain.get_label() 216 | gpu_res = {} 217 | booster = xgb.train(param, dtrain, num_round, evals_result=gpu_res, evals = [], xgb_model = trained_model) 218 | return booster 219 | 220 | def get_best_booster(target_variable, max_interactions, df, astro_columns): 221 | booster = None 222 | best_score = 1 223 | best_booster = None 224 | for current_run in range(max_interactions): 225 | X = df[astro_columns].values 226 | Y = df[target_variable].values 227 | total_test = xgb.DMatrix(X, feature_names = astro_columns) 228 | X_train_1, X_train_2, y_train_1, y_train_2 = ttsplit(X, Y, 229 | test_size=0.3, 230 | random_state=None, 231 | shuffle=True) 232 | booster = create_booster_swing_trade( 233 | ETA, DEPTH, NUM_TREES, 234 | X_train_1, y_train_1, 235 | X_train_2, y_train_2, 236 | astro_columns, booster) 237 | current_score = mse(booster.predict(total_test), Y) 238 | if current_score < best_score: 239 | best_score = current_score 240 | best_booster = booster 241 | gc.collect() 242 | print("{} - {} of {}, {}".format(target_variable, current_run, max_interactions, best_score)) 243 | if best_score < MIN_PRECISION: 244 | break 245 | return best_booster, best_score 246 | 247 | def predict_score(row, booster, df, astro_columns): 248 | matrix_to_predict = row[astro_columns].values 249 | matrix_to_predict = matrix_to_predict.reshape((1,-1)) 250 | row_features = xgb.DMatrix(matrix_to_predict, feature_names = astro_columns) 251 | predicted = booster.predict(row_features)[0] 252 | if predicted > 1: 253 | predicted = 1 254 | if predicted < -1: 255 | predicted = -1 256 | return predicted -------------------------------------------------------------------------------- /notebooks/Predict.price.change.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# pyAstroTrader\n", 8 | "\n", 9 | "## Predict\n", 10 | "\n", 11 | "This notebook is used to predict the future behaviour of the stock prices in the market, using the models created in the ```CreateModel.ipynb``` notebook\n", 12 | "\n", 13 | "First, we need to import the modules that we are going to use:" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": null, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "import os\n", 23 | "import pandas as pd\n", 24 | "import dask.dataframe as dd\n", 25 | "import numpy as np\n", 26 | "import datetime\n", 27 | "import plotly.graph_objects as go\n", 28 | "\n", 29 | "from sklearn.model_selection import KFold\n", 30 | "from sklearn.model_selection import train_test_split as ttsplit\n", 31 | "from sklearn.metrics import mean_squared_error as mse\n", 32 | "\n", 33 | "import xgboost as xgb\n", 34 | "from xgboost import XGBClassifier\n", 35 | "from xgboost import plot_importance\n", 36 | "from xgboost import plot_tree\n", 37 | "\n", 38 | "from IPython.display import display, HTML\n", 39 | "\n", 40 | "import eli5\n", 41 | "\n", 42 | "from pyastrotrader import calculate_chart, calculate_aspects, calculate_transits\n", 43 | "from pyastrotrader.utils import create_input_json\n", 44 | "from pyastrotrader.constants import *\n", 45 | "\n", 46 | "from settings import *\n", 47 | "from helpers import *" 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "metadata": {}, 53 | "source": [ 54 | "We need only to create the dates that we are going to predict as specified in the DAYS_TO_PREDICT configuration variable from settings.py, we will create a list of dictionaries with the correct column name" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": null, 60 | "metadata": {}, 61 | "outputs": [], 62 | "source": [ 63 | "today = datetime.datetime.now().date() + datetime.timedelta(days=+1)\n", 64 | "days_to_process = []\n", 65 | "data_to_dataframe = []\n", 66 | "day = today\n", 67 | "for day_to_predict in range(DAYS_TO_PREDICT):\n", 68 | " day = day + datetime.timedelta(days=1)\n", 69 | " if day.weekday()==5 or day.weekday()==6:\n", 70 | " continue\n", 71 | " day_as_str = day.strftime('%Y-%m-%d')\n", 72 | " days_to_process.append(day_as_str)\n", 73 | " data_to_dataframe.append({ 'CorrectedDate' : day_as_str}) \n", 74 | " " 75 | ] 76 | }, 77 | { 78 | "cell_type": "markdown", 79 | "metadata": {}, 80 | "source": [ 81 | "With the list of dictionaries, we can use the pandas dataframe constructor to create a dataframe with the dates." 82 | ] 83 | }, 84 | { 85 | "cell_type": "code", 86 | "execution_count": null, 87 | "metadata": {}, 88 | "outputs": [], 89 | "source": [ 90 | "StockPrices = pd.DataFrame(data_to_dataframe)" 91 | ] 92 | }, 93 | { 94 | "cell_type": "markdown", 95 | "metadata": {}, 96 | "source": [ 97 | "As we did on the ```CreateModel.ipynb``` notebook, we need to create the natal chart of the selected asset." 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": null, 103 | "metadata": {}, 104 | "outputs": [], 105 | "source": [ 106 | "asset_natal_chart_input = create_input_json(NATAL_DATE, \n", 107 | " DEFAULT_PARAMETERS, \n", 108 | " DEFAULT_CONFIG)\n", 109 | "\n", 110 | "asset_natal_chart = calculate_chart(asset_natal_chart_input)\n", 111 | "dates_to_generate = days_to_process" 112 | ] 113 | }, 114 | { 115 | "cell_type": "markdown", 116 | "metadata": {}, 117 | "source": [ 118 | "Now, for all the dates on the pandas dataframe containing the quotes, we need to generate astrological charts with the list of planets to consider: ```PLANETS_TO_CALCULATE```, their aspects: ```ASPECTS_TO_CALCULATE```" 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": null, 124 | "metadata": {}, 125 | "outputs": [], 126 | "source": [ 127 | "for current_date in dates_to_generate:\n", 128 | " chart_input = create_input_json(current_date + 'T10:00:00-03:00', \n", 129 | " DEFAULT_PARAMETERS, \n", 130 | " DEFAULT_CONFIG)\n", 131 | " charts[current_date] = calculate_chart(chart_input)\n", 132 | " aspects[current_date] = calculate_transits(asset_natal_chart, charts[current_date], PLANETS_TO_CALCULATE, ASPECTS_TO_CALCULATE, 4)\n", 133 | " aspects_transiting[current_date]= calculate_aspects(charts[current_date], PLANETS_TO_CALCULATE, ASPECTS_TO_CALCULATE, 4) " 134 | ] 135 | }, 136 | { 137 | "cell_type": "markdown", 138 | "metadata": {}, 139 | "source": [ 140 | "We have the natal chart and also all the charts for each date in the pandas dataframe, now we need to add to the pandas dataframe, the astrological aspects that occur in each date, we will set only to 1 if there is a aspect occuring or 0 if not, we also will check for aspects on the transiting chart as well as aspects between the natal chart and the transiting chart\n", 141 | "\n", 142 | "**astro_columns** will indicate the name of the columns containing astrological indicators in the pandas dataframe" 143 | ] 144 | }, 145 | { 146 | "cell_type": "code", 147 | "execution_count": null, 148 | "metadata": {}, 149 | "outputs": [], 150 | "source": [ 151 | "astro_columns = []\n", 152 | "\n", 153 | "for current_planet in PLANETS_TO_CALCULATE:\n", 154 | " if current_planet != SATURN:\n", 155 | " column_name=\"ASTRO_{}_POSITION\".format(PLANETS[current_planet]).upper()\n", 156 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 157 | " StockPrices[column_name] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : int(get_degree_for_planet(x, current_planet) / 3), axis =1), meta='int').compute(scheduler='processes')\n", 158 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float', errors='coerce') \n", 159 | " astro_columns.append(column_name) \n", 160 | " for second_planet in PLANETS_TO_CALCULATE:\n", 161 | " if current_planet == second_planet:\n", 162 | " continue\n", 163 | "\n", 164 | " column_name=\"ASTRO_{}_{}_DIFF\".format(PLANETS[current_planet], PLANETS[second_planet]).upper()\n", 165 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 166 | " StockPrices[column_name] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : int(int(get_degree_for_planet(x, current_planet) - get_degree_for_planet(x, second_planet))/ 3), axis =1), meta='int').compute(scheduler='processes')\n", 167 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float', errors='coerce') \n", 168 | " astro_columns.append(column_name) \n", 169 | "\n", 170 | " column_name=\"ASTRO_{}_{}_DIFF_ABS\".format(PLANETS[current_planet], PLANETS[second_planet]).upper()\n", 171 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 172 | " StockPrices[column_name] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : abs(int(get_degree_for_planet(x, current_planet) - get_degree_for_planet(x, second_planet))/ 3), axis =1), meta='int').compute(scheduler='processes')\n", 173 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float', errors='coerce') \n", 174 | " astro_columns.append(column_name) \n", 175 | "\n", 176 | "\n", 177 | "for first_planet in PLANETS_TO_CALCULATE:\n", 178 | " for second_planet in PLANETS_TO_CALCULATE:\n", 179 | " for aspect in ASPECTS_TO_CALCULATE:\n", 180 | " column_name=\"ASTRO_{}_{}_{}\".format(PLANETS[first_planet],ASPECT_NAME[aspect],PLANETS[second_planet]).upper()\n", 181 | " aspect_column_name = column_name\n", 182 | " astro_columns.append(column_name)\n", 183 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 184 | " StockPrices[column_name] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : is_aspected(x, first_planet, second_planet, aspect), axis =1), meta='float').compute(scheduler='processes')\n", 185 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float', errors='coerce')\n", 186 | "\n", 187 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 188 | " column_name=\"ASTRO_TRANSITING_{}_{}_{}\".format(PLANETS[first_planet],ASPECT_NAME[aspect],PLANETS[second_planet]).upper()\n", 189 | " astro_columns.append(column_name)\n", 190 | " StockPrices[column_name] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : is_aspected_transiting(x, first_planet, second_planet, aspect), axis =1), meta='float').compute(scheduler='processes')\n", 191 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float', errors='coerce')" 192 | ] 193 | }, 194 | { 195 | "cell_type": "markdown", 196 | "metadata": {}, 197 | "source": [ 198 | "We need also to determine which planets are retrograde in each date of the pandas dataframe" 199 | ] 200 | }, 201 | { 202 | "cell_type": "code", 203 | "execution_count": null, 204 | "metadata": {}, 205 | "outputs": [], 206 | "source": [ 207 | "for first_planet in []:\n", 208 | " column_name=\"ASTRO_{}_RETROGADE\".format(PLANETS[first_planet]).upper()\n", 209 | " astro_columns.append(column_name)\n", 210 | " StockPrices[column_name] = StockPrices.apply(lambda x:is_retrograde(x, first_planet), axis =1)\n", 211 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float',errors='coerce')" 212 | ] 213 | }, 214 | { 215 | "cell_type": "markdown", 216 | "metadata": {}, 217 | "source": [ 218 | "We need to load the models, which were generated from the ```CreateModel.ipynb``` notebook" 219 | ] 220 | }, 221 | { 222 | "cell_type": "code", 223 | "execution_count": null, 224 | "metadata": {}, 225 | "outputs": [], 226 | "source": [ 227 | "booster_price_change = xgb.Booster()\n", 228 | "\n", 229 | "price_change_model_filename = './output/{}_price_change.model'.format(ASSET_TO_CALCULATE)\n", 230 | "\n", 231 | "booster_price_change.load_model(price_change_model_filename) # load data" 232 | ] 233 | }, 234 | { 235 | "cell_type": "markdown", 236 | "metadata": {}, 237 | "source": [ 238 | "And now, predict the values, using the models created in ```CreateModel.ipynb``` notebook" 239 | ] 240 | }, 241 | { 242 | "cell_type": "markdown", 243 | "metadata": {}, 244 | "source": [ 245 | "As we dont need all the columns from the pandas dataframe, we can specify the target variables and the date as the only one that are necessary..." 246 | ] 247 | }, 248 | { 249 | "cell_type": "markdown", 250 | "metadata": {}, 251 | "source": [ 252 | "And now save the results in 2 excel files: 1 simplified and another with the entire data." 253 | ] 254 | }, 255 | { 256 | "cell_type": "code", 257 | "execution_count": null, 258 | "metadata": {}, 259 | "outputs": [], 260 | "source": [ 261 | "output_excel_file='./output/{}.Predict.xlsx'.format(ASSET_TO_CALCULATE)\n", 262 | "StockPrices.to_excel(output_excel_file)" 263 | ] 264 | }, 265 | { 266 | "cell_type": "code", 267 | "execution_count": null, 268 | "metadata": {}, 269 | "outputs": [], 270 | "source": [ 271 | "output_excel_file='./output/{}.Predict.Simplified.xls'.format(ASSET_TO_CALCULATE)\n", 272 | "CalculatedValue = StockPrices.apply(lambda x:predict_score(x, booster_price_change, StockPrices, astro_columns), axis =1)\n", 273 | "\n", 274 | "if not os.path.isfile(output_excel_file):\n", 275 | " SimplifiedColumns = ['CorrectedDate', \n", 276 | " 'PredictPriceChange' ] \n", 277 | " StockPrices['PredictPriceChange'] = CalculatedValue\n", 278 | " StockPrices[SimplifiedColumns].to_excel(output_excel_file)\n", 279 | "else:\n", 280 | " column = datetime.datetime.strftime(datetime.datetime.today(), '%Y%m%d%H%M%S') + 'PredictPriceChange'\n", 281 | " StockPrices = pd.read_excel(output_excel_file)\n", 282 | " StockPrices[column] = CalculatedValue\n", 283 | " StockPrices.to_excel(output_excel_file, index=False)\n", 284 | " \n", 285 | " " 286 | ] 287 | }, 288 | { 289 | "cell_type": "code", 290 | "execution_count": null, 291 | "metadata": {}, 292 | "outputs": [], 293 | "source": [] 294 | } 295 | ], 296 | "metadata": { 297 | "kernelspec": { 298 | "display_name": "Python 3", 299 | "language": "python", 300 | "name": "python3" 301 | }, 302 | "language_info": { 303 | "codemirror_mode": { 304 | "name": "ipython", 305 | "version": 3 306 | }, 307 | "file_extension": ".py", 308 | "mimetype": "text/x-python", 309 | "name": "python", 310 | "nbconvert_exporter": "python", 311 | "pygments_lexer": "ipython3", 312 | "version": "3.8.1" 313 | } 314 | }, 315 | "nbformat": 4, 316 | "nbformat_minor": 4 317 | } 318 | -------------------------------------------------------------------------------- /notebooks/Predict.swing.trade.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# pyAstroTrader\n", 8 | "\n", 9 | "## Predict\n", 10 | "\n", 11 | "This notebook is used to predict the future behaviour of the stock prices in the market, using the models created in the ```CreateModel.ipynb``` notebook\n", 12 | "\n", 13 | "First, we need to import the modules that we are going to use:" 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": null, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "import os\n", 23 | "import pandas as pd\n", 24 | "import dask.dataframe as dd\n", 25 | "import numpy as np\n", 26 | "import datetime\n", 27 | "import plotly.graph_objects as go\n", 28 | "\n", 29 | "from sklearn.model_selection import KFold\n", 30 | "from sklearn.model_selection import train_test_split as ttsplit\n", 31 | "from sklearn.metrics import mean_squared_error as mse\n", 32 | "\n", 33 | "import xgboost as xgb\n", 34 | "from xgboost import XGBClassifier\n", 35 | "from xgboost import plot_importance\n", 36 | "from xgboost import plot_tree\n", 37 | "\n", 38 | "from IPython.display import display, HTML\n", 39 | "\n", 40 | "import eli5\n", 41 | "\n", 42 | "from pyastrotrader import calculate_chart, calculate_aspects, calculate_transits\n", 43 | "from pyastrotrader.utils import create_input_json\n", 44 | "from pyastrotrader.constants import *\n", 45 | "\n", 46 | "from settings import *\n", 47 | "from helpers import *" 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "metadata": {}, 53 | "source": [ 54 | "We need only to create the dates that we are going to predict as specified in the DAYS_TO_PREDICT configuration variable from settings.py, we will create a list of dictionaries with the correct column name" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": null, 60 | "metadata": {}, 61 | "outputs": [], 62 | "source": [ 63 | "today = datetime.datetime.now().date() + datetime.timedelta(days=+1)\n", 64 | "days_to_process = []\n", 65 | "data_to_dataframe = []\n", 66 | "day = today\n", 67 | "for day_to_predict in range(DAYS_TO_PREDICT):\n", 68 | " day = day + datetime.timedelta(days=1)\n", 69 | " if day.weekday()==5 or day.weekday()==6:\n", 70 | " continue\n", 71 | " day_as_str = day.strftime('%Y-%m-%d')\n", 72 | " days_to_process.append(day_as_str)\n", 73 | " data_to_dataframe.append({ 'CorrectedDate' : day_as_str}) \n", 74 | " " 75 | ] 76 | }, 77 | { 78 | "cell_type": "markdown", 79 | "metadata": {}, 80 | "source": [ 81 | "With the list of dictionaries, we can use the pandas dataframe constructor to create a dataframe with the dates." 82 | ] 83 | }, 84 | { 85 | "cell_type": "code", 86 | "execution_count": null, 87 | "metadata": {}, 88 | "outputs": [], 89 | "source": [ 90 | "StockPrices = pd.DataFrame(data_to_dataframe)" 91 | ] 92 | }, 93 | { 94 | "cell_type": "markdown", 95 | "metadata": {}, 96 | "source": [ 97 | "As we did on the ```CreateModel.ipynb``` notebook, we need to create the natal chart of the selected asset." 98 | ] 99 | }, 100 | { 101 | "cell_type": "code", 102 | "execution_count": null, 103 | "metadata": {}, 104 | "outputs": [], 105 | "source": [ 106 | "asset_natal_chart_input = create_input_json(NATAL_DATE, \n", 107 | " DEFAULT_PARAMETERS, \n", 108 | " DEFAULT_CONFIG)\n", 109 | "\n", 110 | "asset_natal_chart = calculate_chart(asset_natal_chart_input)\n", 111 | "dates_to_generate = days_to_process" 112 | ] 113 | }, 114 | { 115 | "cell_type": "markdown", 116 | "metadata": {}, 117 | "source": [ 118 | "Now, for all the dates on the pandas dataframe containing the quotes, we need to generate astrological charts with the list of planets to consider: ```PLANETS_TO_CALCULATE```, their aspects: ```ASPECTS_TO_CALCULATE```" 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": null, 124 | "metadata": {}, 125 | "outputs": [], 126 | "source": [ 127 | "for current_date in dates_to_generate:\n", 128 | " chart_input = create_input_json(current_date + 'T10:00:00-03:00', \n", 129 | " DEFAULT_PARAMETERS, \n", 130 | " DEFAULT_CONFIG)\n", 131 | " charts[current_date] = calculate_chart(chart_input)\n", 132 | " aspects[current_date] = calculate_transits(asset_natal_chart, charts[current_date], PLANETS_TO_CALCULATE, ASPECTS_TO_CALCULATE, 4)\n", 133 | " aspects_transiting[current_date]= calculate_aspects(charts[current_date], PLANETS_TO_CALCULATE, ASPECTS_TO_CALCULATE, 4) " 134 | ] 135 | }, 136 | { 137 | "cell_type": "markdown", 138 | "metadata": {}, 139 | "source": [ 140 | "We have the natal chart and also all the charts for each date in the pandas dataframe, now we need to add to the pandas dataframe, the astrological aspects that occur in each date, we will set only to 1 if there is a aspect occuring or 0 if not, we also will check for aspects on the transiting chart as well as aspects between the natal chart and the transiting chart\n", 141 | "\n", 142 | "**astro_columns** will indicate the name of the columns containing astrological indicators in the pandas dataframe" 143 | ] 144 | }, 145 | { 146 | "cell_type": "code", 147 | "execution_count": null, 148 | "metadata": {}, 149 | "outputs": [], 150 | "source": [ 151 | "astro_columns = []\n", 152 | "\n", 153 | "for current_planet in PLANETS_TO_CALCULATE:\n", 154 | " if current_planet != SATURN:\n", 155 | " column_name=\"ASTRO_{}_POSITION\".format(PLANETS[current_planet]).upper()\n", 156 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 157 | " StockPrices[column_name] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : int(get_degree_for_planet(x, current_planet) / 3), axis =1), meta='int').compute(scheduler='processes')\n", 158 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float', errors='coerce') \n", 159 | " astro_columns.append(column_name) \n", 160 | " for second_planet in PLANETS_TO_CALCULATE:\n", 161 | " if current_planet == second_planet:\n", 162 | " continue\n", 163 | "\n", 164 | " column_name=\"ASTRO_{}_{}_DIFF\".format(PLANETS[current_planet], PLANETS[second_planet]).upper()\n", 165 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 166 | " StockPrices[column_name] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : int(int(get_degree_for_planet(x, current_planet) - get_degree_for_planet(x, second_planet))/ 3), axis =1), meta='int').compute(scheduler='processes')\n", 167 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float', errors='coerce') \n", 168 | " astro_columns.append(column_name) \n", 169 | "\n", 170 | " column_name=\"ASTRO_{}_{}_DIFF_ABS\".format(PLANETS[current_planet], PLANETS[second_planet]).upper()\n", 171 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 172 | " StockPrices[column_name] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : abs(int(get_degree_for_planet(x, current_planet) - get_degree_for_planet(x, second_planet))/ 3), axis =1), meta='int').compute(scheduler='processes')\n", 173 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float', errors='coerce') \n", 174 | " astro_columns.append(column_name) \n", 175 | "\n", 176 | "\n", 177 | "for first_planet in PLANETS_TO_CALCULATE:\n", 178 | " for second_planet in PLANETS_TO_CALCULATE:\n", 179 | " for aspect in ASPECTS_TO_CALCULATE:\n", 180 | " column_name=\"ASTRO_{}_{}_{}\".format(PLANETS[first_planet],ASPECT_NAME[aspect],PLANETS[second_planet]).upper()\n", 181 | " aspect_column_name = column_name\n", 182 | " astro_columns.append(column_name)\n", 183 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 184 | " StockPrices[column_name] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : is_aspected(x, first_planet, second_planet, aspect), axis =1), meta='float').compute(scheduler='processes')\n", 185 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float', errors='coerce')\n", 186 | "\n", 187 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 188 | " column_name=\"ASTRO_TRANSITING_{}_{}_{}\".format(PLANETS[first_planet],ASPECT_NAME[aspect],PLANETS[second_planet]).upper()\n", 189 | " astro_columns.append(column_name)\n", 190 | " StockPrices[column_name] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : is_aspected_transiting(x, first_planet, second_planet, aspect), axis =1), meta='float').compute(scheduler='processes')\n", 191 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float', errors='coerce')" 192 | ] 193 | }, 194 | { 195 | "cell_type": "markdown", 196 | "metadata": {}, 197 | "source": [ 198 | "We need also to determine which planets are retrograde in each date of the pandas dataframe" 199 | ] 200 | }, 201 | { 202 | "cell_type": "code", 203 | "execution_count": null, 204 | "metadata": {}, 205 | "outputs": [], 206 | "source": [ 207 | "for first_planet in []:\n", 208 | " column_name=\"ASTRO_{}_RETROGADE\".format(PLANETS[first_planet]).upper()\n", 209 | " astro_columns.append(column_name)\n", 210 | " StockPrices[column_name] = StockPrices.apply(lambda x:is_retrograde(x, first_planet), axis =1)\n", 211 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float',errors='coerce')" 212 | ] 213 | }, 214 | { 215 | "cell_type": "markdown", 216 | "metadata": {}, 217 | "source": [ 218 | "We need to load the models, which were generated from the ```CreateModel.ipynb``` notebook" 219 | ] 220 | }, 221 | { 222 | "cell_type": "code", 223 | "execution_count": null, 224 | "metadata": {}, 225 | "outputs": [], 226 | "source": [ 227 | "booster_price_change = xgb.Booster()\n", 228 | "\n", 229 | "price_change_model_filename = './output/{}_swing_trade.model'.format(ASSET_TO_CALCULATE)\n", 230 | "\n", 231 | "booster_price_change.load_model(price_change_model_filename) # load data" 232 | ] 233 | }, 234 | { 235 | "cell_type": "markdown", 236 | "metadata": {}, 237 | "source": [ 238 | "And now, predict the values, using the models created in ```CreateModel.ipynb``` notebook" 239 | ] 240 | }, 241 | { 242 | "cell_type": "markdown", 243 | "metadata": {}, 244 | "source": [ 245 | "As we dont need all the columns from the pandas dataframe, we can specify the target variables and the date as the only one that are necessary..." 246 | ] 247 | }, 248 | { 249 | "cell_type": "markdown", 250 | "metadata": {}, 251 | "source": [ 252 | "And now save the results in 2 excel files: 1 simplified and another with the entire data." 253 | ] 254 | }, 255 | { 256 | "cell_type": "code", 257 | "execution_count": null, 258 | "metadata": {}, 259 | "outputs": [], 260 | "source": [ 261 | "output_excel_file='./output/{}.Predict.swing.trade.xlsx'.format(ASSET_TO_CALCULATE)\n", 262 | "StockPrices.to_excel(output_excel_file)" 263 | ] 264 | }, 265 | { 266 | "cell_type": "code", 267 | "execution_count": null, 268 | "metadata": {}, 269 | "outputs": [], 270 | "source": [ 271 | "output_excel_file='./output/{}.Predict.swing.trade.Simplified.xls'.format(ASSET_TO_CALCULATE)\n", 272 | "CalculatedValue = StockPrices.apply(lambda x:predict_score(x, booster_price_change, StockPrices, astro_columns), axis =1)\n", 273 | "\n", 274 | "if not os.path.isfile(output_excel_file):\n", 275 | " SimplifiedColumns = ['CorrectedDate', \n", 276 | " 'PredictSwingTrade' ] \n", 277 | " StockPrices['PredictSwingTrade'] = CalculatedValue\n", 278 | " StockPrices[SimplifiedColumns].to_excel(output_excel_file)\n", 279 | "else:\n", 280 | " column = datetime.datetime.strftime(datetime.datetime.today(), '%Y%m%d%H%M%S') + 'PredictSwingTrade'\n", 281 | " StockPrices = pd.read_excel(output_excel_file)\n", 282 | " StockPrices[column] = CalculatedValue\n", 283 | " StockPrices.to_excel(output_excel_file, index=False)\n", 284 | " \n", 285 | " " 286 | ] 287 | }, 288 | { 289 | "cell_type": "code", 290 | "execution_count": null, 291 | "metadata": {}, 292 | "outputs": [], 293 | "source": [] 294 | } 295 | ], 296 | "metadata": { 297 | "kernelspec": { 298 | "display_name": "Python 3", 299 | "language": "python", 300 | "name": "python3" 301 | }, 302 | "language_info": { 303 | "codemirror_mode": { 304 | "name": "ipython", 305 | "version": 3 306 | }, 307 | "file_extension": ".py", 308 | "mimetype": "text/x-python", 309 | "name": "python", 310 | "nbconvert_exporter": "python", 311 | "pygments_lexer": "ipython3", 312 | "version": "3.8.1" 313 | } 314 | }, 315 | "nbformat": 4, 316 | "nbformat_minor": 4 317 | } 318 | -------------------------------------------------------------------------------- /notebooks/CreateModel.swing.trade.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# pyAstroTrader\n", 8 | "\n", 9 | "# Create Model\n", 10 | "\n", 11 | "After downloading the quotes data for the asset selected with the ASSET_TO_CALCULATE environment variable, we need to add the astrological data to the quotes and then generate a XGBoost model\n", 12 | "\n", 13 | "First of all, we need to import the models that we need to process." 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": null, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "import os\n", 23 | "import gc\n", 24 | "import multiprocessing as mp\n", 25 | "import pickle\n", 26 | "\n", 27 | "import pandas as pd\n", 28 | "import dask.dataframe as dd\n", 29 | "from dask.multiprocessing import get\n", 30 | "import numpy as np\n", 31 | "import plotly.graph_objects as go\n", 32 | "\n", 33 | "from sklearn.model_selection import KFold\n", 34 | "from sklearn.model_selection import train_test_split as ttsplit\n", 35 | "from sklearn.metrics import mean_squared_error as mse\n", 36 | "\n", 37 | "import xgboost as xgb\n", 38 | "from xgboost import XGBClassifier\n", 39 | "from xgboost import plot_importance\n", 40 | "from xgboost import plot_tree\n", 41 | "\n", 42 | "from IPython.display import display, HTML\n", 43 | "\n", 44 | "import eli5\n", 45 | "\n" 46 | ] 47 | }, 48 | { 49 | "cell_type": "markdown", 50 | "metadata": {}, 51 | "source": [ 52 | "```pyastrotrader``` is a python module that we created, in order to calculate astrological charts based on specific dates, and also to calculate aspects between charts" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": null, 58 | "metadata": {}, 59 | "outputs": [], 60 | "source": [ 61 | "from pyastrotrader import calculate_chart, calculate_aspects, calculate_transits, get_degrees, get_degree\n", 62 | "from pyastrotrader.utils import create_input_json\n", 63 | "from pyastrotrader.constants import *" 64 | ] 65 | }, 66 | { 67 | "cell_type": "markdown", 68 | "metadata": {}, 69 | "source": [ 70 | "Import all settings and helper functions that we will use in the next cells" 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "execution_count": null, 76 | "metadata": {}, 77 | "outputs": [], 78 | "source": [ 79 | "from settings import *\n", 80 | "from helpers import *\n", 81 | "\n", 82 | "USING_CACHED_DATAFRAME = False\n", 83 | "CACHE_FILE = './output/{}.{}.cache'.format(ASSET_TO_CALCULATE, datetime.datetime.strftime(datetime.datetime.today(), '%Y%m%d') )\n", 84 | "CACHE_ASTRO_COLUMNS = './output/{}.{}.astro.cache'.format(ASSET_TO_CALCULATE, datetime.datetime.strftime(datetime.datetime.today(), '%Y%m%d') )\n", 85 | "\n", 86 | "if os.path.isfile(CACHE_FILE):\n", 87 | " USING_CACHED_DATAFRAME = True" 88 | ] 89 | }, 90 | { 91 | "cell_type": "markdown", 92 | "metadata": {}, 93 | "source": [ 94 | "Read the CSV file with the quotes downloaded, and also create a counter column to help in the calculated columns below" 95 | ] 96 | }, 97 | { 98 | "cell_type": "code", 99 | "execution_count": null, 100 | "metadata": {}, 101 | "outputs": [], 102 | "source": [ 103 | "if not USING_CACHED_DATAFRAME:\n", 104 | " StockPrices = pd.read_csv(\"{}.csv\".format(SOURCE_FILE))\n", 105 | " StockPrices['Counter'] = np.arange(len(StockPrices))" 106 | ] 107 | }, 108 | { 109 | "cell_type": "markdown", 110 | "metadata": {}, 111 | "source": [ 112 | "Using several helper functions from ```helpers.py``` module, for each day we need to determine several indicators like:\n", 113 | "* The current trend\n", 114 | "* the future trend\n", 115 | "* If there was a change in the trend ( a swing trade opportunity )\n", 116 | "* current volatility for the previous days\n", 117 | "* and many other indicators" 118 | ] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": null, 123 | "metadata": {}, 124 | "outputs": [], 125 | "source": [ 126 | "if not USING_CACHED_DATAFRAME:\n", 127 | " max_counter = StockPrices['Counter'].max()\n", 128 | "\n", 129 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 130 | " StockPrices['CorrectedDate'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : correct_date(x), axis =1)).compute(scheduler='processes')\n", 131 | " StockPrices['PreviousStartPrice'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : get_previous_stock_price(StockPrices, x, SWING_TRADE_DURATION), axis =1), meta='float').compute(scheduler='processes')\n", 132 | " StockPrices['FutureFinalPrice'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : get_future_stock_price(StockPrices, x, max_counter, SWING_TRADE_DURATION), axis =1 ), meta='float').compute(scheduler='processes')\n", 133 | " StockPrices['PreviousStartDate'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : get_previous_stock_date(StockPrices, x, SWING_TRADE_DURATION), axis =1 ), meta='float').compute(scheduler='processes')\n", 134 | " StockPrices['FutureFinalDate'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : get_future_stock_date(StockPrices, x, max_counter, SWING_TRADE_DURATION), axis =1 ), meta='float').compute(scheduler='processes')\n", 135 | "\n", 136 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 137 | " StockPrices['CurrentTrend'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : calculate_current_trend(x), axis = 1), meta='float').compute(scheduler='processes')\n", 138 | "\n", 139 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 140 | " StockPrices['FutureTrend'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : calculate_future_trend(x), axis = 1), meta='float').compute(scheduler='processes')\n", 141 | "\n", 142 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 143 | " StockPrices['SwingStrength'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : calculate_swing_strenght(x), axis =1), meta='float').compute(scheduler='processes')\n", 144 | " StockPrices['IntradayVolatility'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : calculate_intraday_volatility(StockPrices, x, SWING_TRADE_DURATION), axis =1), meta='float').compute(scheduler='processes')\n", 145 | "\n", 146 | " StockPrices['FutureTrendMax'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : get_future_stock_max_price(StockPrices, x, max_counter, SWING_TRADE_DURATION), axis = 1), meta='float').compute(scheduler='processes')\n", 147 | " StockPrices['FutureTrendMin'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : get_future_stock_min_price(StockPrices, x, max_counter, SWING_TRADE_DURATION), axis = 1), meta='float').compute(scheduler='processes')\n", 148 | "\n", 149 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 150 | " StockPrices['IsSwingBottom'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : detect_swing_trade_bottom(x, df, SWING_TRADE_DURATION, max_counter), axis =1), meta='float').compute(scheduler='processes')\n", 151 | "\n", 152 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 153 | " StockPrices['StockIncreasedPrice'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : detect_price_increase(x, STAGNATION_THRESHOLD), axis =1), meta='float').compute(scheduler='processes')\n", 154 | " StockPrices['StockDecreasedPrice'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : detect_price_decrease(x, STAGNATION_THRESHOLD), axis =1), meta='float').compute(scheduler='processes')\n", 155 | " StockPrices['StockStagnated'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : detect_price_stagnated(x, STAGNATION_THRESHOLD), axis =1), meta='float').compute(scheduler='processes')\n", 156 | " StockPrices['StockPriceChange'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : calculate_price_change(StockPrices, x), axis =1), meta='float').compute(scheduler='processes')\n", 157 | "\n", 158 | " StockPrices['TARGET_IS_SWING_BOTTOM'] = StockPrices['IsSwingBottom']\n", 159 | " StockPrices['TARGET_PRICE_INCREASE'] = StockPrices['StockIncreasedPrice']\n", 160 | " StockPrices['TARGET_PRICE_DECREASE'] = StockPrices['StockDecreasedPrice']\n", 161 | " StockPrices['TARGET_PRICE_STAGNATION'] = StockPrices['StockStagnated']\n", 162 | " StockPrices['TARGET_PRICE_CHANGE'] = StockPrices['StockPriceChange'] \n" 163 | ] 164 | }, 165 | { 166 | "cell_type": "markdown", 167 | "metadata": {}, 168 | "source": [ 169 | "After all the analisys, we can generate a excel file in order to help debug the indicators generated above" 170 | ] 171 | }, 172 | { 173 | "cell_type": "code", 174 | "execution_count": null, 175 | "metadata": {}, 176 | "outputs": [], 177 | "source": [ 178 | "if not USING_CACHED_DATAFRAME:\n", 179 | " output_excel_file='./output/{}.swing.trade.Analisys.xlsx'.format(ASSET_TO_CALCULATE)\n", 180 | " StockPricesToExcel = StockPrices.copy()\n", 181 | " StockPricesToExcel = StockPricesToExcel.sort_values(by=['CorrectedDate'], axis=0, ascending=False)\n", 182 | " StockPricesToExcel.to_excel(output_excel_file)" 183 | ] 184 | }, 185 | { 186 | "cell_type": "markdown", 187 | "metadata": {}, 188 | "source": [ 189 | "To debug the indicators, we can plot a stock chart with the swing indication, but this is commented out as it requires a lot of computational resources." 190 | ] 191 | }, 192 | { 193 | "cell_type": "code", 194 | "execution_count": null, 195 | "metadata": {}, 196 | "outputs": [], 197 | "source": [ 198 | "\"\"\"\n", 199 | "swing_to_chart = []\n", 200 | "for index, current_swing in StockPrices[StockPrices['IsSwing'] == 1].iterrows():\n", 201 | " swing_to_chart.append(dict(\n", 202 | " x0=current_swing['CorrectedDate'], \n", 203 | " x1=current_swing['CorrectedDate'], \n", 204 | " y0=0, \n", 205 | " y1=1, \n", 206 | " xref='x', \n", 207 | " yref='paper',\n", 208 | " line_width=2))\n", 209 | "\"\"\"" 210 | ] 211 | }, 212 | { 213 | "cell_type": "code", 214 | "execution_count": null, 215 | "metadata": {}, 216 | "outputs": [], 217 | "source": [ 218 | "\"\"\"\n", 219 | "fig = go.Figure(data=[go.Candlestick(\n", 220 | " x=StockPrices['CorrectedDate'],\n", 221 | " open=StockPrices['Open'],\n", 222 | " high=StockPrices['High'],\n", 223 | " low=StockPrices['Low'],\n", 224 | " close=StockPrices['Price'])])\n", 225 | "fig.update_layout(\n", 226 | " title=\"{} Detected Swing Trade Opportunities\".format(ASSET_TO_CALCULATE),\n", 227 | " width=1000,\n", 228 | " height=500,\n", 229 | " xaxis_rangeslider_visible=False,\n", 230 | " shapes=swing_to_chart,\n", 231 | " margin=go.layout.Margin(\n", 232 | " l=0,\n", 233 | " r=0,\n", 234 | " b=0,\n", 235 | " t=30,\n", 236 | " pad=4\n", 237 | " ), \n", 238 | ")\n", 239 | "#fig.show()\n", 240 | "\"\"\"" 241 | ] 242 | }, 243 | { 244 | "cell_type": "markdown", 245 | "metadata": {}, 246 | "source": [ 247 | "Well, in order to calculate the astrological indicators for the current ASSET_TO_CALCULATE, we need to generate a natal chart of the asset, which traditionally is the first trade date on the current exchange " 248 | ] 249 | }, 250 | { 251 | "cell_type": "code", 252 | "execution_count": null, 253 | "metadata": {}, 254 | "outputs": [], 255 | "source": [ 256 | "if not USING_CACHED_DATAFRAME:\n", 257 | " asset_natal_chart_input = create_input_json(NATAL_DATE, \n", 258 | " DEFAULT_PARAMETERS, \n", 259 | " DEFAULT_CONFIG)\n", 260 | "\n", 261 | " asset_natal_chart = calculate_chart(asset_natal_chart_input)\n", 262 | " dates_to_generate = list(StockPrices['CorrectedDate'])" 263 | ] 264 | }, 265 | { 266 | "cell_type": "markdown", 267 | "metadata": {}, 268 | "source": [ 269 | "Now, for all the dates on the pandas dataframe containing the quotes, we need to generate astrological charts with the list of planets to consider: ```PLANETS_TO_CALCULATE```, their aspects: ```ASPECTS_TO_CALCULATE```" 270 | ] 271 | }, 272 | { 273 | "cell_type": "code", 274 | "execution_count": null, 275 | "metadata": {}, 276 | "outputs": [], 277 | "source": [ 278 | "if not USING_CACHED_DATAFRAME:\n", 279 | " def generate_charts(current_date):\n", 280 | " chart_input = create_input_json(current_date + 'T10:00:00-03:00', \n", 281 | " DEFAULT_PARAMETERS, \n", 282 | " DEFAULT_CONFIG)\n", 283 | " current_chart = calculate_chart(chart_input)\n", 284 | " return (current_date,\n", 285 | " current_chart, \n", 286 | " calculate_transits(asset_natal_chart, current_chart, PLANETS_TO_CALCULATE, ASPECTS_TO_CALCULATE, 4),\n", 287 | " calculate_aspects(current_chart, PLANETS_TO_CALCULATE, ASPECTS_TO_CALCULATE, 4))\n", 288 | "\n", 289 | " with mp.Pool(processes = NPARTITIONS) as p:\n", 290 | " results = p.map(generate_charts, dates_to_generate)\n", 291 | "\n", 292 | " for x in results:\n", 293 | " charts[x[0]] = x[1]\n", 294 | " aspects[x[0]] = x[2]\n", 295 | " aspects_transiting[x[0]] = x[3]" 296 | ] 297 | }, 298 | { 299 | "cell_type": "markdown", 300 | "metadata": {}, 301 | "source": [ 302 | "We have the natal chart and also all the charts for each date in the pandas dataframe, now we need to add to the pandas dataframe, the astrological aspects that occur in each date, we will set only to 1 if there is a aspect occuring or 0 if not, we also will check for aspects on the transiting chart as well as aspects between the natal chart and the transiting chart\n", 303 | "\n", 304 | "**astro_columns** will indicate the name of the columns containing astrological indicators in the pandas dataframe" 305 | ] 306 | }, 307 | { 308 | "cell_type": "code", 309 | "execution_count": null, 310 | "metadata": {}, 311 | "outputs": [], 312 | "source": [ 313 | "if not USING_CACHED_DATAFRAME:\n", 314 | " astro_columns = []\n", 315 | "\n", 316 | " for current_planet in PLANETS_TO_CALCULATE:\n", 317 | " if current_planet != SATURN:\n", 318 | " column_name=\"ASTRO_{}_POSITION\".format(PLANETS[current_planet]).upper()\n", 319 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 320 | " StockPrices[column_name] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : int(get_degree_for_planet(x, current_planet) / 3), axis =1), meta='int').compute(scheduler='processes')\n", 321 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float', errors='coerce') \n", 322 | " astro_columns.append(column_name) \n", 323 | " for second_planet in PLANETS_TO_CALCULATE:\n", 324 | " if current_planet == second_planet:\n", 325 | " continue\n", 326 | " \n", 327 | " column_name=\"ASTRO_{}_{}_DIFF\".format(PLANETS[current_planet], PLANETS[second_planet]).upper()\n", 328 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 329 | " StockPrices[column_name] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : int(int(get_degree_for_planet(x, current_planet) - get_degree_for_planet(x, second_planet))/ 3), axis =1), meta='int').compute(scheduler='processes')\n", 330 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float', errors='coerce') \n", 331 | " astro_columns.append(column_name) \n", 332 | " \n", 333 | " column_name=\"ASTRO_{}_{}_DIFF_ABS\".format(PLANETS[current_planet], PLANETS[second_planet]).upper()\n", 334 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 335 | " StockPrices[column_name] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : abs(int(get_degree_for_planet(x, current_planet) - get_degree_for_planet(x, second_planet))/ 3), axis =1), meta='int').compute(scheduler='processes')\n", 336 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float', errors='coerce') \n", 337 | " astro_columns.append(column_name) \n", 338 | " \n", 339 | "\n", 340 | " for first_planet in PLANETS_TO_CALCULATE:\n", 341 | " for second_planet in PLANETS_TO_CALCULATE:\n", 342 | " for aspect in ASPECTS_TO_CALCULATE:\n", 343 | " column_name=\"ASTRO_{}_{}_{}\".format(PLANETS[first_planet],ASPECT_NAME[aspect],PLANETS[second_planet]).upper()\n", 344 | " aspect_column_name = column_name\n", 345 | " astro_columns.append(column_name)\n", 346 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 347 | " StockPrices[column_name] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : is_aspected(x, first_planet, second_planet, aspect), axis =1), meta='float').compute(scheduler='processes')\n", 348 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float', errors='coerce')\n", 349 | "\n", 350 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 351 | " column_name=\"ASTRO_TRANSITING_{}_{}_{}\".format(PLANETS[first_planet],ASPECT_NAME[aspect],PLANETS[second_planet]).upper()\n", 352 | " astro_columns.append(column_name)\n", 353 | " StockPrices[column_name] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : is_aspected_transiting(x, first_planet, second_planet, aspect), axis =1), meta='float').compute(scheduler='processes')\n", 354 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float', errors='coerce') \n" 355 | ] 356 | }, 357 | { 358 | "cell_type": "markdown", 359 | "metadata": {}, 360 | "source": [ 361 | "We need also to determine which planets are retrograde in each date of the pandas dataframe" 362 | ] 363 | }, 364 | { 365 | "cell_type": "code", 366 | "execution_count": null, 367 | "metadata": {}, 368 | "outputs": [], 369 | "source": [ 370 | "if not USING_CACHED_DATAFRAME:\n", 371 | " for first_planet in []:\n", 372 | " column_name=\"ASTRO_{}_RETROGADE\".format(PLANETS[first_planet]).upper()\n", 373 | " astro_columns.append(column_name)\n", 374 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 375 | " StockPrices[column_name] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : is_retrograde(x, first_planet), axis =1), meta='float').compute(scheduler='processes')\n", 376 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float',errors='coerce')\n", 377 | " \n", 378 | "if USING_CACHED_DATAFRAME: \n", 379 | " StockPrices = pd.read_pickle(CACHE_FILE)\n", 380 | " with open(CACHE_ASTRO_COLUMNS, 'rb') as f:\n", 381 | " astro_columns = pickle.load(f) \n", 382 | "else:\n", 383 | " StockPrices.to_pickle(CACHE_FILE)\n", 384 | " with open(CACHE_ASTRO_COLUMNS, 'wb') as f:\n", 385 | " pickle.dump(astro_columns, f)" 386 | ] 387 | }, 388 | { 389 | "cell_type": "markdown", 390 | "metadata": {}, 391 | "source": [ 392 | "After the pandas dataframe has been populated with the astrological indicators, we can now train the XGBoost models in order to predict the following target variables:\n", 393 | "* Price Increase: There is a increase in price after that date\n", 394 | "* Price Decrease: There is a decrease in price after that date\n", 395 | "* Price Stagnation: There is a stagnation in price after that date\n", 396 | "* Swing Trade: There is a change in trend after that date\n", 397 | " \n", 398 | "**Important to notice that we will use as input only the astro_columns columns which contains astrological indicators**" 399 | ] 400 | }, 401 | { 402 | "cell_type": "code", 403 | "execution_count": null, 404 | "metadata": {}, 405 | "outputs": [], 406 | "source": [ 407 | "booster_price_change, score_price_change = get_best_booster('TARGET_IS_SWING_BOTTOM', MAX_INTERACTIONS, StockPrices, astro_columns)\n", 408 | "print(\"Best Score for Swing Trade Model:{}\".format(score_price_change))" 409 | ] 410 | }, 411 | { 412 | "cell_type": "markdown", 413 | "metadata": {}, 414 | "source": [ 415 | "We can now save each model score in a text file" 416 | ] 417 | }, 418 | { 419 | "cell_type": "code", 420 | "execution_count": null, 421 | "metadata": {}, 422 | "outputs": [], 423 | "source": [ 424 | "if not USING_CACHED_DATAFRAME:\n", 425 | " score_price_change_file_name = './output/{}.score.swing.trade.txt'.format(ASSET_TO_CALCULATE)\n", 426 | "\n", 427 | " with open(score_price_change_file_name, 'w') as f:\n", 428 | " f.write(\"{}:{}\".format(ASSET_TO_CALCULATE,str(score_price_change)))" 429 | ] 430 | }, 431 | { 432 | "cell_type": "markdown", 433 | "metadata": {}, 434 | "source": [ 435 | "We can also calculate for each model the relevant astrological variables, used in each model" 436 | ] 437 | }, 438 | { 439 | "cell_type": "code", 440 | "execution_count": null, 441 | "metadata": {}, 442 | "outputs": [], 443 | "source": [ 444 | "if not USING_CACHED_DATAFRAME:\n", 445 | " relevant_features_price_change = sorted( ((v,k) for k,v in booster_price_change.get_score().items()), reverse=True)\n", 446 | "\n", 447 | " display(relevant_features_price_change)" 448 | ] 449 | }, 450 | { 451 | "cell_type": "markdown", 452 | "metadata": {}, 453 | "source": [ 454 | "We can now write such features to text files in order to improve the analisys of the model." 455 | ] 456 | }, 457 | { 458 | "cell_type": "code", 459 | "execution_count": null, 460 | "metadata": {}, 461 | "outputs": [], 462 | "source": [ 463 | "if not USING_CACHED_DATAFRAME:\n", 464 | " def write_features(f, list_to_write):\n", 465 | " for item_to_write in list_to_write:\n", 466 | " f.write('{}-{}'.format(ASSET_TO_CALCULATE,str(item_to_write).replace(')','').replace('(','').replace('\\'','').replace(' ','') + '\\n'))\n", 467 | " \n", 468 | " features_price_change_file_name = './output/{}.features.swing.trade.txt'.format(ASSET_TO_CALCULATE)\n", 469 | "\n", 470 | " with open(features_price_change_file_name, 'w') as f:\n", 471 | " write_features(f,relevant_features_price_change) " 472 | ] 473 | }, 474 | { 475 | "cell_type": "markdown", 476 | "metadata": {}, 477 | "source": [ 478 | "We can check the predicted value for each model on the pandas dataframe, creating a column for it " 479 | ] 480 | }, 481 | { 482 | "cell_type": "code", 483 | "execution_count": null, 484 | "metadata": {}, 485 | "outputs": [], 486 | "source": [ 487 | "if not USING_CACHED_DATAFRAME:\n", 488 | " StockPrices['PredictSwingTrade'] = StockPrices.apply(lambda x:predict_score(x, booster_price_change, StockPrices, astro_columns), axis =1)" 489 | ] 490 | }, 491 | { 492 | "cell_type": "markdown", 493 | "metadata": {}, 494 | "source": [ 495 | "And save the model for further use on the ```Predict.ipynb``` notebook" 496 | ] 497 | }, 498 | { 499 | "cell_type": "code", 500 | "execution_count": null, 501 | "metadata": {}, 502 | "outputs": [], 503 | "source": [ 504 | "booster_price_change.save_model('./output/{}_swing_trade.model'.format(ASSET_TO_CALCULATE))" 505 | ] 506 | }, 507 | { 508 | "cell_type": "markdown", 509 | "metadata": {}, 510 | "source": [ 511 | "And save a excel with all the data produced..." 512 | ] 513 | }, 514 | { 515 | "cell_type": "code", 516 | "execution_count": null, 517 | "metadata": {}, 518 | "outputs": [], 519 | "source": [ 520 | "if not USING_CACHED_DATAFRAME:\n", 521 | " output_excel_file='./output/{}.swing.trade.Analisys.xlsx'.format(ASSET_TO_CALCULATE) \n", 522 | " StockPrices.to_excel(output_excel_file)" 523 | ] 524 | }, 525 | { 526 | "cell_type": "markdown", 527 | "metadata": {}, 528 | "source": [ 529 | "The plotting of charts has been commented out as it is very resource consuming..." 530 | ] 531 | }, 532 | { 533 | "cell_type": "code", 534 | "execution_count": null, 535 | "metadata": {}, 536 | "outputs": [], 537 | "source": [ 538 | "\"\"\"\n", 539 | "swing_to_chart = []\n", 540 | "for index, current_swing in StockPrices[StockPrices['PredictSwingTradeScore'] > 0.9].iterrows():\n", 541 | " swing_to_chart.append(dict(\n", 542 | " x0=current_swing['CorrectedDate'], \n", 543 | " x1=current_swing['CorrectedDate'], \n", 544 | " y0=0, \n", 545 | " y1=1, \n", 546 | " xref='x', \n", 547 | " yref='paper',\n", 548 | " line_width=2))\n", 549 | "\"\"\" " 550 | ] 551 | }, 552 | { 553 | "cell_type": "code", 554 | "execution_count": null, 555 | "metadata": {}, 556 | "outputs": [], 557 | "source": [ 558 | "\"\"\"\n", 559 | "fig = go.Figure(data=[go.Candlestick(\n", 560 | " x=StockPrices['CorrectedDate'],\n", 561 | " open=StockPrices['Open'],\n", 562 | " high=StockPrices['High'],\n", 563 | " low=StockPrices['Low'],\n", 564 | " close=StockPrices['Price'])])\n", 565 | "fig.update_layout(\n", 566 | " title=\"{} Swing Trade Opportunities detected by XGBoost\".format(ASSET_TO_CALCULATE),\n", 567 | " width=1000,\n", 568 | " height=500,\n", 569 | " xaxis_rangeslider_visible=False,\n", 570 | " shapes=swing_to_chart,\n", 571 | " margin=go.layout.Margin(\n", 572 | " l=0,\n", 573 | " r=0,\n", 574 | " b=0,\n", 575 | " t=30,\n", 576 | " pad=4\n", 577 | " ), \n", 578 | ")\n", 579 | "#fig.show()\n", 580 | "\"\"\"" 581 | ] 582 | }, 583 | { 584 | "cell_type": "code", 585 | "execution_count": null, 586 | "metadata": {}, 587 | "outputs": [], 588 | "source": [ 589 | "\"\"\"\n", 590 | "swing_to_chart = []\n", 591 | "for index, current_swing in StockPrices[StockPrices['PredictPriceIncreaseScore'] > 5].iterrows():\n", 592 | " swing_to_chart.append(dict(\n", 593 | " x0=current_swing['CorrectedDate'], \n", 594 | " x1=current_swing['CorrectedDate'], \n", 595 | " y0=0, \n", 596 | " y1=1, \n", 597 | " xref='x', \n", 598 | " yref='paper',\n", 599 | " line_width=2))\n", 600 | "\"\"\" " 601 | ] 602 | }, 603 | { 604 | "cell_type": "code", 605 | "execution_count": null, 606 | "metadata": {}, 607 | "outputs": [], 608 | "source": [ 609 | "\"\"\"\n", 610 | "fig = go.Figure(data=[go.Candlestick(\n", 611 | " x=StockPrices['CorrectedDate'],\n", 612 | " open=StockPrices['Open'],\n", 613 | " high=StockPrices['High'],\n", 614 | " low=StockPrices['Low'],\n", 615 | " close=StockPrices['Price'])])\n", 616 | "fig.update_layout(\n", 617 | " title=\"{} Price Increase Opportunities detected by XGBoost (Min {}%)\".format(ASSET_TO_CALCULATE, STAGNATION_THRESHOLD),\n", 618 | " width=1000,\n", 619 | " height=500,\n", 620 | " xaxis_rangeslider_visible=False,\n", 621 | " shapes=swing_to_chart,\n", 622 | " margin=go.layout.Margin(\n", 623 | " l=0,\n", 624 | " r=0,\n", 625 | " b=0,\n", 626 | " t=30,\n", 627 | " pad=4\n", 628 | " ), \n", 629 | ")\n", 630 | "#fig.show()\n", 631 | "\"\"\"" 632 | ] 633 | }, 634 | { 635 | "cell_type": "code", 636 | "execution_count": null, 637 | "metadata": {}, 638 | "outputs": [], 639 | "source": [] 640 | }, 641 | { 642 | "cell_type": "code", 643 | "execution_count": null, 644 | "metadata": {}, 645 | "outputs": [], 646 | "source": [] 647 | } 648 | ], 649 | "metadata": { 650 | "kernelspec": { 651 | "display_name": "Python 3", 652 | "language": "python", 653 | "name": "python3" 654 | }, 655 | "language_info": { 656 | "codemirror_mode": { 657 | "name": "ipython", 658 | "version": 3 659 | }, 660 | "file_extension": ".py", 661 | "mimetype": "text/x-python", 662 | "name": "python", 663 | "nbconvert_exporter": "python", 664 | "pygments_lexer": "ipython3", 665 | "version": "3.8.1" 666 | } 667 | }, 668 | "nbformat": 4, 669 | "nbformat_minor": 4 670 | } 671 | -------------------------------------------------------------------------------- /notebooks/CreateModel.price.change.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# pyAstroTrader\n", 8 | "\n", 9 | "# Create Model\n", 10 | "\n", 11 | "After downloading the quotes data for the asset selected with the ASSET_TO_CALCULATE environment variable, we need to add the astrological data to the quotes and then generate a XGBoost model\n", 12 | "\n", 13 | "First of all, we need to import the models that we need to process." 14 | ] 15 | }, 16 | { 17 | "cell_type": "code", 18 | "execution_count": null, 19 | "metadata": {}, 20 | "outputs": [], 21 | "source": [ 22 | "import os\n", 23 | "import gc\n", 24 | "import multiprocessing as mp\n", 25 | "import pickle\n", 26 | "\n", 27 | "import pandas as pd\n", 28 | "import dask.dataframe as dd\n", 29 | "from dask.multiprocessing import get\n", 30 | "import numpy as np\n", 31 | "import plotly.graph_objects as go\n", 32 | "\n", 33 | "from sklearn.model_selection import KFold\n", 34 | "from sklearn.model_selection import train_test_split as ttsplit\n", 35 | "from sklearn.metrics import mean_squared_error as mse\n", 36 | "\n", 37 | "import xgboost as xgb\n", 38 | "from xgboost import XGBClassifier\n", 39 | "from xgboost import plot_importance\n", 40 | "from xgboost import plot_tree\n", 41 | "\n", 42 | "from IPython.display import display, HTML\n", 43 | "\n", 44 | "import eli5\n", 45 | "\n" 46 | ] 47 | }, 48 | { 49 | "cell_type": "markdown", 50 | "metadata": {}, 51 | "source": [ 52 | "```pyastrotrader``` is a python module that we created, in order to calculate astrological charts based on specific dates, and also to calculate aspects between charts" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": null, 58 | "metadata": {}, 59 | "outputs": [], 60 | "source": [ 61 | "from pyastrotrader import calculate_chart, calculate_aspects, calculate_transits, get_degrees, get_degree\n", 62 | "from pyastrotrader.utils import create_input_json\n", 63 | "from pyastrotrader.constants import *" 64 | ] 65 | }, 66 | { 67 | "cell_type": "markdown", 68 | "metadata": {}, 69 | "source": [ 70 | "Import all settings and helper functions that we will use in the next cells" 71 | ] 72 | }, 73 | { 74 | "cell_type": "code", 75 | "execution_count": null, 76 | "metadata": {}, 77 | "outputs": [], 78 | "source": [ 79 | "from settings import *\n", 80 | "from helpers import *\n", 81 | "\n", 82 | "USING_CACHED_DATAFRAME = False\n", 83 | "CACHE_FILE = './output/{}.{}.cache'.format(ASSET_TO_CALCULATE, datetime.datetime.strftime(datetime.datetime.today(), '%Y%m%d') )\n", 84 | "CACHE_ASTRO_COLUMNS = './output/{}.{}.astro.cache'.format(ASSET_TO_CALCULATE, datetime.datetime.strftime(datetime.datetime.today(), '%Y%m%d') )\n", 85 | "\n", 86 | "if os.path.isfile(CACHE_FILE):\n", 87 | " USING_CACHED_DATAFRAME = True" 88 | ] 89 | }, 90 | { 91 | "cell_type": "markdown", 92 | "metadata": {}, 93 | "source": [ 94 | "Read the CSV file with the quotes downloaded, and also create a counter column to help in the calculated columns below" 95 | ] 96 | }, 97 | { 98 | "cell_type": "code", 99 | "execution_count": null, 100 | "metadata": {}, 101 | "outputs": [], 102 | "source": [ 103 | "if not USING_CACHED_DATAFRAME:\n", 104 | " StockPrices = pd.read_csv(\"{}.csv\".format(SOURCE_FILE))\n", 105 | " StockPrices['Counter'] = np.arange(len(StockPrices))" 106 | ] 107 | }, 108 | { 109 | "cell_type": "markdown", 110 | "metadata": {}, 111 | "source": [ 112 | "Using several helper functions from ```helpers.py``` module, for each day we need to determine several indicators like:\n", 113 | "* The current trend\n", 114 | "* the future trend\n", 115 | "* If there was a change in the trend ( a swing trade opportunity )\n", 116 | "* current volatility for the previous days\n", 117 | "* and many other indicators" 118 | ] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": null, 123 | "metadata": {}, 124 | "outputs": [], 125 | "source": [ 126 | "if not USING_CACHED_DATAFRAME:\n", 127 | " max_counter = StockPrices['Counter'].max()\n", 128 | "\n", 129 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 130 | " StockPrices['CorrectedDate'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : correct_date(x), axis =1)).compute(scheduler='processes')\n", 131 | " StockPrices['PreviousStartPrice'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : get_previous_stock_price(StockPrices, x, SWING_TRADE_DURATION), axis =1), meta='float').compute(scheduler='processes')\n", 132 | " StockPrices['FutureFinalPrice'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : get_future_stock_price(StockPrices, x, max_counter, SWING_TRADE_DURATION), axis =1 ), meta='float').compute(scheduler='processes')\n", 133 | " StockPrices['PreviousStartDate'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : get_previous_stock_date(StockPrices, x, SWING_TRADE_DURATION), axis =1 ), meta='float').compute(scheduler='processes')\n", 134 | " StockPrices['FutureFinalDate'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : get_future_stock_date(StockPrices, x, max_counter, SWING_TRADE_DURATION), axis =1 ), meta='float').compute(scheduler='processes')\n", 135 | "\n", 136 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 137 | " StockPrices['CurrentTrend'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : calculate_current_trend(x), axis = 1), meta='float').compute(scheduler='processes')\n", 138 | "\n", 139 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 140 | " StockPrices['FutureTrend'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : calculate_future_trend(x), axis = 1), meta='float').compute(scheduler='processes')\n", 141 | "\n", 142 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 143 | " StockPrices['SwingStrength'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : calculate_swing_strenght(x), axis =1), meta='float').compute(scheduler='processes')\n", 144 | " StockPrices['IntradayVolatility'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : calculate_intraday_volatility(StockPrices, x, SWING_TRADE_DURATION), axis =1), meta='float').compute(scheduler='processes')\n", 145 | "\n", 146 | " StockPrices['FutureTrendMax'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : get_future_stock_max_price(StockPrices, x, max_counter, SWING_TRADE_DURATION), axis = 1), meta='float').compute(scheduler='processes')\n", 147 | " StockPrices['FutureTrendMin'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : get_future_stock_min_price(StockPrices, x, max_counter, SWING_TRADE_DURATION), axis = 1), meta='float').compute(scheduler='processes')\n", 148 | "\n", 149 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 150 | " StockPrices['IsSwing'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : detect_swing_trade(x, SWING_EXPECTED_VOLATILITY), axis =1), meta='float').compute(scheduler='processes')\n", 151 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 152 | " StockPrices['IsSwing'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : clean_swing_trade(StockPrices, x, SWING_EXPECTED_VOLATILITY), axis =1), meta='float').compute(scheduler='processes')\n", 153 | "\n", 154 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 155 | " StockPrices['StockIncreasedPrice'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : detect_price_increase(x, STAGNATION_THRESHOLD), axis =1), meta='float').compute(scheduler='processes')\n", 156 | " StockPrices['StockDecreasedPrice'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : detect_price_decrease(x, STAGNATION_THRESHOLD), axis =1), meta='float').compute(scheduler='processes')\n", 157 | " StockPrices['StockStagnated'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : detect_price_stagnated(x, STAGNATION_THRESHOLD), axis =1), meta='float').compute(scheduler='processes')\n", 158 | " StockPrices['StockPriceChange'] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : calculate_price_change(StockPrices, x), axis =1), meta='float').compute(scheduler='processes')\n", 159 | "\n", 160 | " StockPrices['TARGET_IS_SWING'] = StockPrices['IsSwing']\n", 161 | " StockPrices['TARGET_PRICE_INCREASE'] = StockPrices['StockIncreasedPrice']\n", 162 | " StockPrices['TARGET_PRICE_DECREASE'] = StockPrices['StockDecreasedPrice']\n", 163 | " StockPrices['TARGET_PRICE_STAGNATION'] = StockPrices['StockStagnated']\n", 164 | " StockPrices['TARGET_PRICE_CHANGE'] = StockPrices['StockPriceChange'] \n" 165 | ] 166 | }, 167 | { 168 | "cell_type": "markdown", 169 | "metadata": {}, 170 | "source": [ 171 | "After all the analisys, we can generate a excel file in order to help debug the indicators generated above" 172 | ] 173 | }, 174 | { 175 | "cell_type": "code", 176 | "execution_count": null, 177 | "metadata": {}, 178 | "outputs": [], 179 | "source": [ 180 | "if not USING_CACHED_DATAFRAME:\n", 181 | " output_excel_file='./output/{}.Analisys.xlsx'.format(ASSET_TO_CALCULATE)\n", 182 | " StockPrices.to_excel(output_excel_file)" 183 | ] 184 | }, 185 | { 186 | "cell_type": "markdown", 187 | "metadata": {}, 188 | "source": [ 189 | "To debug the indicators, we can plot a stock chart with the swing indication, but this is commented out as it requires a lot of computational resources." 190 | ] 191 | }, 192 | { 193 | "cell_type": "code", 194 | "execution_count": null, 195 | "metadata": {}, 196 | "outputs": [], 197 | "source": [ 198 | "\"\"\"\n", 199 | "swing_to_chart = []\n", 200 | "for index, current_swing in StockPrices[StockPrices['IsSwing'] == 1].iterrows():\n", 201 | " swing_to_chart.append(dict(\n", 202 | " x0=current_swing['CorrectedDate'], \n", 203 | " x1=current_swing['CorrectedDate'], \n", 204 | " y0=0, \n", 205 | " y1=1, \n", 206 | " xref='x', \n", 207 | " yref='paper',\n", 208 | " line_width=2))\n", 209 | "\"\"\"" 210 | ] 211 | }, 212 | { 213 | "cell_type": "code", 214 | "execution_count": null, 215 | "metadata": {}, 216 | "outputs": [], 217 | "source": [ 218 | "\"\"\"\n", 219 | "fig = go.Figure(data=[go.Candlestick(\n", 220 | " x=StockPrices['CorrectedDate'],\n", 221 | " open=StockPrices['Open'],\n", 222 | " high=StockPrices['High'],\n", 223 | " low=StockPrices['Low'],\n", 224 | " close=StockPrices['Price'])])\n", 225 | "fig.update_layout(\n", 226 | " title=\"{} Detected Swing Trade Opportunities\".format(ASSET_TO_CALCULATE),\n", 227 | " width=1000,\n", 228 | " height=500,\n", 229 | " xaxis_rangeslider_visible=False,\n", 230 | " shapes=swing_to_chart,\n", 231 | " margin=go.layout.Margin(\n", 232 | " l=0,\n", 233 | " r=0,\n", 234 | " b=0,\n", 235 | " t=30,\n", 236 | " pad=4\n", 237 | " ), \n", 238 | ")\n", 239 | "#fig.show()\n", 240 | "\"\"\"" 241 | ] 242 | }, 243 | { 244 | "cell_type": "markdown", 245 | "metadata": {}, 246 | "source": [ 247 | "Well, in order to calculate the astrological indicators for the current ASSET_TO_CALCULATE, we need to generate a natal chart of the asset, which traditionally is the first trade date on the current exchange " 248 | ] 249 | }, 250 | { 251 | "cell_type": "code", 252 | "execution_count": null, 253 | "metadata": {}, 254 | "outputs": [], 255 | "source": [ 256 | "if not USING_CACHED_DATAFRAME:\n", 257 | " asset_natal_chart_input = create_input_json(NATAL_DATE, \n", 258 | " DEFAULT_PARAMETERS, \n", 259 | " DEFAULT_CONFIG)\n", 260 | "\n", 261 | " asset_natal_chart = calculate_chart(asset_natal_chart_input)\n", 262 | " dates_to_generate = list(StockPrices['CorrectedDate'])" 263 | ] 264 | }, 265 | { 266 | "cell_type": "markdown", 267 | "metadata": {}, 268 | "source": [ 269 | "Now, for all the dates on the pandas dataframe containing the quotes, we need to generate astrological charts with the list of planets to consider: ```PLANETS_TO_CALCULATE```, their aspects: ```ASPECTS_TO_CALCULATE```" 270 | ] 271 | }, 272 | { 273 | "cell_type": "code", 274 | "execution_count": null, 275 | "metadata": {}, 276 | "outputs": [], 277 | "source": [ 278 | "if not USING_CACHED_DATAFRAME:\n", 279 | " def generate_charts(current_date):\n", 280 | " chart_input = create_input_json(current_date + 'T10:00:00-03:00', \n", 281 | " DEFAULT_PARAMETERS, \n", 282 | " DEFAULT_CONFIG)\n", 283 | " current_chart = calculate_chart(chart_input)\n", 284 | " return (current_date,\n", 285 | " current_chart, \n", 286 | " calculate_transits(asset_natal_chart, current_chart, PLANETS_TO_CALCULATE, ASPECTS_TO_CALCULATE, 4),\n", 287 | " calculate_aspects(current_chart, PLANETS_TO_CALCULATE, ASPECTS_TO_CALCULATE, 4))\n", 288 | "\n", 289 | " with mp.Pool(processes = NPARTITIONS) as p:\n", 290 | " results = p.map(generate_charts, dates_to_generate)\n", 291 | "\n", 292 | " for x in results:\n", 293 | " charts[x[0]] = x[1]\n", 294 | " aspects[x[0]] = x[2]\n", 295 | " aspects_transiting[x[0]] = x[3]" 296 | ] 297 | }, 298 | { 299 | "cell_type": "markdown", 300 | "metadata": {}, 301 | "source": [ 302 | "We have the natal chart and also all the charts for each date in the pandas dataframe, now we need to add to the pandas dataframe, the astrological aspects that occur in each date, we will set only to 1 if there is a aspect occuring or 0 if not, we also will check for aspects on the transiting chart as well as aspects between the natal chart and the transiting chart\n", 303 | "\n", 304 | "**astro_columns** will indicate the name of the columns containing astrological indicators in the pandas dataframe" 305 | ] 306 | }, 307 | { 308 | "cell_type": "code", 309 | "execution_count": null, 310 | "metadata": {}, 311 | "outputs": [], 312 | "source": [ 313 | "if not USING_CACHED_DATAFRAME:\n", 314 | " astro_columns = []\n", 315 | "\n", 316 | " for current_planet in PLANETS_TO_CALCULATE:\n", 317 | " if current_planet != SATURN:\n", 318 | " column_name=\"ASTRO_{}_POSITION\".format(PLANETS[current_planet]).upper()\n", 319 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 320 | " StockPrices[column_name] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : int(get_degree_for_planet(x, current_planet) / 3), axis =1), meta='int').compute(scheduler='processes')\n", 321 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float', errors='coerce') \n", 322 | " astro_columns.append(column_name) \n", 323 | " for second_planet in PLANETS_TO_CALCULATE:\n", 324 | " if current_planet == second_planet:\n", 325 | " continue\n", 326 | " \n", 327 | " column_name=\"ASTRO_{}_{}_DIFF\".format(PLANETS[current_planet], PLANETS[second_planet]).upper()\n", 328 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 329 | " StockPrices[column_name] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : int(int(get_degree_for_planet(x, current_planet) - get_degree_for_planet(x, second_planet))/ 3), axis =1), meta='int').compute(scheduler='processes')\n", 330 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float', errors='coerce') \n", 331 | " astro_columns.append(column_name) \n", 332 | " \n", 333 | " column_name=\"ASTRO_{}_{}_DIFF_ABS\".format(PLANETS[current_planet], PLANETS[second_planet]).upper()\n", 334 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 335 | " StockPrices[column_name] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : abs(int(get_degree_for_planet(x, current_planet) - get_degree_for_planet(x, second_planet))/ 3), axis =1), meta='int').compute(scheduler='processes')\n", 336 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float', errors='coerce') \n", 337 | " astro_columns.append(column_name) \n", 338 | " \n", 339 | "\n", 340 | " for first_planet in PLANETS_TO_CALCULATE:\n", 341 | " for second_planet in PLANETS_TO_CALCULATE:\n", 342 | " for aspect in ASPECTS_TO_CALCULATE:\n", 343 | " column_name=\"ASTRO_{}_{}_{}\".format(PLANETS[first_planet],ASPECT_NAME[aspect],PLANETS[second_planet]).upper()\n", 344 | " aspect_column_name = column_name\n", 345 | " astro_columns.append(column_name)\n", 346 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 347 | " StockPrices[column_name] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : is_aspected(x, first_planet, second_planet, aspect), axis =1), meta='float').compute(scheduler='processes')\n", 348 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float', errors='coerce')\n", 349 | "\n", 350 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 351 | " column_name=\"ASTRO_TRANSITING_{}_{}_{}\".format(PLANETS[first_planet],ASPECT_NAME[aspect],PLANETS[second_planet]).upper()\n", 352 | " astro_columns.append(column_name)\n", 353 | " StockPrices[column_name] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : is_aspected_transiting(x, first_planet, second_planet, aspect), axis =1), meta='float').compute(scheduler='processes')\n", 354 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float', errors='coerce') \n" 355 | ] 356 | }, 357 | { 358 | "cell_type": "markdown", 359 | "metadata": {}, 360 | "source": [ 361 | "We need also to determine which planets are retrograde in each date of the pandas dataframe" 362 | ] 363 | }, 364 | { 365 | "cell_type": "code", 366 | "execution_count": null, 367 | "metadata": {}, 368 | "outputs": [], 369 | "source": [ 370 | "if not USING_CACHED_DATAFRAME:\n", 371 | " for first_planet in []:\n", 372 | " column_name=\"ASTRO_{}_RETROGADE\".format(PLANETS[first_planet]).upper()\n", 373 | " astro_columns.append(column_name)\n", 374 | " StockPricesDask = dd.from_pandas(StockPrices, npartitions=NPARTITIONS)\n", 375 | " StockPrices[column_name] = StockPricesDask.map_partitions(lambda df : df.apply(lambda x : is_retrograde(x, first_planet), axis =1), meta='float').compute(scheduler='processes')\n", 376 | " StockPrices[column_name] = pd.to_numeric(StockPrices[column_name], downcast='float',errors='coerce')\n", 377 | " \n", 378 | "if USING_CACHED_DATAFRAME: \n", 379 | " StockPrices = pd.read_pickle(CACHE_FILE)\n", 380 | " with open(CACHE_ASTRO_COLUMNS, 'rb') as f:\n", 381 | " astro_columns = pickle.load(f) \n", 382 | "else:\n", 383 | " StockPrices.to_pickle(CACHE_FILE)\n", 384 | " with open(CACHE_ASTRO_COLUMNS, 'wb') as f:\n", 385 | " pickle.dump(astro_columns, f)" 386 | ] 387 | }, 388 | { 389 | "cell_type": "markdown", 390 | "metadata": {}, 391 | "source": [ 392 | "After the pandas dataframe has been populated with the astrological indicators, we can now train the XGBoost models in order to predict the following target variables:\n", 393 | "* Price Increase: There is a increase in price after that date\n", 394 | "* Price Decrease: There is a decrease in price after that date\n", 395 | "* Price Stagnation: There is a stagnation in price after that date\n", 396 | "* Swing Trade: There is a change in trend after that date\n", 397 | " \n", 398 | "**Important to notice that we will use as input only the astro_columns columns which contains astrological indicators**" 399 | ] 400 | }, 401 | { 402 | "cell_type": "code", 403 | "execution_count": null, 404 | "metadata": {}, 405 | "outputs": [], 406 | "source": [ 407 | "booster_price_change, score_price_change = get_best_booster('TARGET_PRICE_CHANGE', MAX_INTERACTIONS, StockPrices, astro_columns)\n", 408 | "print(\"Best Score for Price Change Model:{}\".format(score_price_change))" 409 | ] 410 | }, 411 | { 412 | "cell_type": "markdown", 413 | "metadata": {}, 414 | "source": [ 415 | "We can now save each model score in a text file" 416 | ] 417 | }, 418 | { 419 | "cell_type": "code", 420 | "execution_count": null, 421 | "metadata": {}, 422 | "outputs": [], 423 | "source": [ 424 | "if not USING_CACHED_DATAFRAME:\n", 425 | " score_price_change_file_name = './output/{}.score.price.change.txt'.format(ASSET_TO_CALCULATE)\n", 426 | "\n", 427 | " with open(score_price_change_file_name, 'w') as f:\n", 428 | " f.write(\"{}:{}\".format(ASSET_TO_CALCULATE,str(score_price_change)))" 429 | ] 430 | }, 431 | { 432 | "cell_type": "markdown", 433 | "metadata": {}, 434 | "source": [ 435 | "We can also calculate for each model the relevant astrological variables, used in each model" 436 | ] 437 | }, 438 | { 439 | "cell_type": "code", 440 | "execution_count": null, 441 | "metadata": {}, 442 | "outputs": [], 443 | "source": [ 444 | "if not USING_CACHED_DATAFRAME:\n", 445 | " relevant_features_price_change = sorted( ((v,k) for k,v in booster_price_change.get_score().items()), reverse=True)\n", 446 | "\n", 447 | " display(relevant_features_price_change)" 448 | ] 449 | }, 450 | { 451 | "cell_type": "markdown", 452 | "metadata": {}, 453 | "source": [ 454 | "We can now write such features to text files in order to improve the analisys of the model." 455 | ] 456 | }, 457 | { 458 | "cell_type": "code", 459 | "execution_count": null, 460 | "metadata": {}, 461 | "outputs": [], 462 | "source": [ 463 | "if not USING_CACHED_DATAFRAME:\n", 464 | " def write_features(f, list_to_write):\n", 465 | " for item_to_write in list_to_write:\n", 466 | " f.write('{}-{}'.format(ASSET_TO_CALCULATE,str(item_to_write).replace(')','').replace('(','').replace('\\'','').replace(' ','') + '\\n'))\n", 467 | " \n", 468 | " features_price_change_file_name = './output/{}.features.price.change.txt'.format(ASSET_TO_CALCULATE)\n", 469 | "\n", 470 | " with open(features_price_change_file_name, 'w') as f:\n", 471 | " write_features(f,relevant_features_price_change) " 472 | ] 473 | }, 474 | { 475 | "cell_type": "markdown", 476 | "metadata": {}, 477 | "source": [ 478 | "We can check the predicted value for each model on the pandas dataframe, creating a column for it " 479 | ] 480 | }, 481 | { 482 | "cell_type": "code", 483 | "execution_count": null, 484 | "metadata": {}, 485 | "outputs": [], 486 | "source": [ 487 | "if not USING_CACHED_DATAFRAME:\n", 488 | " StockPrices['PredictPriceChange'] = StockPrices.apply(lambda x:predict_score(x, booster_price_change, StockPrices, astro_columns), axis =1)" 489 | ] 490 | }, 491 | { 492 | "cell_type": "markdown", 493 | "metadata": {}, 494 | "source": [ 495 | "And save the model for further use on the ```Predict.ipynb``` notebook" 496 | ] 497 | }, 498 | { 499 | "cell_type": "code", 500 | "execution_count": null, 501 | "metadata": {}, 502 | "outputs": [], 503 | "source": [ 504 | "booster_price_change.save_model('./output/{}_price_change.model'.format(ASSET_TO_CALCULATE))" 505 | ] 506 | }, 507 | { 508 | "cell_type": "markdown", 509 | "metadata": {}, 510 | "source": [ 511 | "And save a excel with all the data produced..." 512 | ] 513 | }, 514 | { 515 | "cell_type": "code", 516 | "execution_count": null, 517 | "metadata": {}, 518 | "outputs": [], 519 | "source": [ 520 | "if not USING_CACHED_DATAFRAME:\n", 521 | " output_excel_file='./output/{}.Analisys.xlsx'.format(ASSET_TO_CALCULATE) \n", 522 | " StockPrices.to_excel(output_excel_file)" 523 | ] 524 | }, 525 | { 526 | "cell_type": "markdown", 527 | "metadata": {}, 528 | "source": [ 529 | "The plotting of charts has been commented out as it is very resource consuming..." 530 | ] 531 | }, 532 | { 533 | "cell_type": "code", 534 | "execution_count": null, 535 | "metadata": {}, 536 | "outputs": [], 537 | "source": [ 538 | "\"\"\"\n", 539 | "swing_to_chart = []\n", 540 | "for index, current_swing in StockPrices[StockPrices['PredictSwingTradeScore'] > 0.9].iterrows():\n", 541 | " swing_to_chart.append(dict(\n", 542 | " x0=current_swing['CorrectedDate'], \n", 543 | " x1=current_swing['CorrectedDate'], \n", 544 | " y0=0, \n", 545 | " y1=1, \n", 546 | " xref='x', \n", 547 | " yref='paper',\n", 548 | " line_width=2))\n", 549 | "\"\"\" " 550 | ] 551 | }, 552 | { 553 | "cell_type": "code", 554 | "execution_count": null, 555 | "metadata": {}, 556 | "outputs": [], 557 | "source": [ 558 | "\"\"\"\n", 559 | "fig = go.Figure(data=[go.Candlestick(\n", 560 | " x=StockPrices['CorrectedDate'],\n", 561 | " open=StockPrices['Open'],\n", 562 | " high=StockPrices['High'],\n", 563 | " low=StockPrices['Low'],\n", 564 | " close=StockPrices['Price'])])\n", 565 | "fig.update_layout(\n", 566 | " title=\"{} Swing Trade Opportunities detected by XGBoost\".format(ASSET_TO_CALCULATE),\n", 567 | " width=1000,\n", 568 | " height=500,\n", 569 | " xaxis_rangeslider_visible=False,\n", 570 | " shapes=swing_to_chart,\n", 571 | " margin=go.layout.Margin(\n", 572 | " l=0,\n", 573 | " r=0,\n", 574 | " b=0,\n", 575 | " t=30,\n", 576 | " pad=4\n", 577 | " ), \n", 578 | ")\n", 579 | "#fig.show()\n", 580 | "\"\"\"" 581 | ] 582 | }, 583 | { 584 | "cell_type": "code", 585 | "execution_count": null, 586 | "metadata": {}, 587 | "outputs": [], 588 | "source": [ 589 | "\"\"\"\n", 590 | "swing_to_chart = []\n", 591 | "for index, current_swing in StockPrices[StockPrices['PredictPriceIncreaseScore'] > 5].iterrows():\n", 592 | " swing_to_chart.append(dict(\n", 593 | " x0=current_swing['CorrectedDate'], \n", 594 | " x1=current_swing['CorrectedDate'], \n", 595 | " y0=0, \n", 596 | " y1=1, \n", 597 | " xref='x', \n", 598 | " yref='paper',\n", 599 | " line_width=2))\n", 600 | "\"\"\" " 601 | ] 602 | }, 603 | { 604 | "cell_type": "code", 605 | "execution_count": null, 606 | "metadata": {}, 607 | "outputs": [], 608 | "source": [ 609 | "\"\"\"\n", 610 | "fig = go.Figure(data=[go.Candlestick(\n", 611 | " x=StockPrices['CorrectedDate'],\n", 612 | " open=StockPrices['Open'],\n", 613 | " high=StockPrices['High'],\n", 614 | " low=StockPrices['Low'],\n", 615 | " close=StockPrices['Price'])])\n", 616 | "fig.update_layout(\n", 617 | " title=\"{} Price Increase Opportunities detected by XGBoost (Min {}%)\".format(ASSET_TO_CALCULATE, STAGNATION_THRESHOLD),\n", 618 | " width=1000,\n", 619 | " height=500,\n", 620 | " xaxis_rangeslider_visible=False,\n", 621 | " shapes=swing_to_chart,\n", 622 | " margin=go.layout.Margin(\n", 623 | " l=0,\n", 624 | " r=0,\n", 625 | " b=0,\n", 626 | " t=30,\n", 627 | " pad=4\n", 628 | " ), \n", 629 | ")\n", 630 | "#fig.show()\n", 631 | "\"\"\"" 632 | ] 633 | }, 634 | { 635 | "cell_type": "code", 636 | "execution_count": null, 637 | "metadata": {}, 638 | "outputs": [], 639 | "source": [] 640 | }, 641 | { 642 | "cell_type": "code", 643 | "execution_count": null, 644 | "metadata": {}, 645 | "outputs": [], 646 | "source": [] 647 | } 648 | ], 649 | "metadata": { 650 | "kernelspec": { 651 | "display_name": "Python 3", 652 | "language": "python", 653 | "name": "python3" 654 | }, 655 | "language_info": { 656 | "codemirror_mode": { 657 | "name": "ipython", 658 | "version": 3 659 | }, 660 | "file_extension": ".py", 661 | "mimetype": "text/x-python", 662 | "name": "python", 663 | "nbconvert_exporter": "python", 664 | "pygments_lexer": "ipython3", 665 | "version": "3.8.1" 666 | } 667 | }, 668 | "nbformat": 4, 669 | "nbformat_minor": 4 670 | } 671 | --------------------------------------------------------------------------------