{ "cells": [ { "cell_type": "markdown", "id": "c9dc167c", "metadata": {}, "source": [ "# Easy to use trading bot in Python with MA, MACD, RSI, Stochastic, BB, MFI, and Candlestick Patterns, with backtesting, optimization, and live paper trading (using TA, TA-Lib, vectorbt, Alpaca) + 13 TRADING STRATEGIES TESTED" ] }, { "cell_type": "markdown", "id": "12b40fe8", "metadata": {}, "source": [ "# Disclaimer\n", "\n", "### Before we start coding, you should know that this tutorial and this bot is created for educational purposes. The bot uses 'paper account' to trade (does not use real money) and this tutorial is not a financial advice for you, just a short programming tutorial. \n", "\n", "And that being said, let's start.\n", "\n", "## The tutorial is 'beginner friendly', so you can see here at first:\n", "## - how to set up your computer environment for running the bot,\n", "## - how to run the bot and test 13 trading strategies with no programming skills.\n", "## And after that you can see more in depth explanaition of what's inside the bot and how to improve it.\n", "\n", "### The bot is divided to 3 parts (requires 7 steps/cells/clicks to run). The 3 parts are:\n", "\n", "I. The only thing you have to change to make the bot work (insert your private keys).\n", "\n", "II. Things you don't need to change, but might to easily make the bot better (changing the strategy, parameters, etc.). \n", "\n", "III. Things you don't need to change, but might if you want to make more advanced changes to the bot.\n", "\n", "## 7 steps (cells / clicks) to run the bot\n", "1. INSERT YOUR KEYS TO THE BOT (the only thing you have to change to make the bot work) !!!\n", "2. INSTALL (optional) AND IMPORT EXTERNAL TOOLS (LIBRARIES, PACKAGES, AND MODULES)\n", "3. CHOOSE AN ASSET TO TRADE\n", "4. SHAPE THE BRAIN OF THE BOT (declare which and how indicators and candlestick patterns should be used to create trading signals (buy / sell / do nothing))\n", "5. DECLARE EASY TO CHANGE PARAMETERS FOR BACKTESTING, OPTIMIZATION, AND LIVE TRADING \n", "6. CREATE OTHER NECESSARY PARAMETERS AND FUNCTIONS FOR BACKTESTING, OPTIMIZATION, AND LIVE TRADING\n", "7. DO SOME BACKTESTING (optional) AND START LIVE TRADING WITH PAPER TRADING ACCOUNT\n", "\n", "## The 13 tested trading strategies are:\n", "1. BUY when CLOSE PRICE crosses over MA ==> SELL when CLOSE PRICE crosses under MA\n", "2. BUY when FAST MA crosses over SLOW MA ==> SELL when FAST MA crosses under SLOW MA\n", "3. BUY when MACD crosses over MACD SIGNAL ==> SELL when MACD crosses under MACD SIGNAL\n", "4. BUY when RSI crosses under RSI OVERSOLD THRESHOLD ==> SELL when RSI crosses over RSI OVERBOUGHT THRESHOLD\n", "5. BUY when STOCHASTIC crosses under STOCHASTIC OVERSOLD THRESHOLD ==> SELL when STOCHASTIC crosses over STOCHASTIC OVERBOUGHT THRESHOLD\n", "6. BUY when CLOSE PRICE crosses under LOWER BOLLINGER BAND ==> SELL when CLOSE PRICE crosses over HIGHER BOLLINGER BAND\n", "7. BUY when MFI crosses under MFI ENTRY THRESHOLD ==> SELL when MFI crosses over MFI EXIT THRESHOLD\n", "8. BUY when at least 1 of 5 CANDLESTICK PATTERNS shows to BUY ==> SELL when at least 1 of 5 CANDLESTICK PATTERNS shows to SELL \n", "9. BUY when 1 of 7 TECHNICAL INDICATORS shows to BUY (CP > MA or FAST MA > SLOW MA or MACD > MACD SIGNAL or RSI > RSI ENTRY or STOCHASTIC > STOCHASTIC ENTRY or CP < BB LOW or MFI > MFI ENTRY)* AND 1 of 5 CANDLESTICK PATTERNS shows to BUY ==> SELL when 1 of 7 TECHNICAL INDICATORS shows to SELL (CP < MA or FAST MA < SLOW MA or MACD < MACD SIGNAL or RSI > RSI EXIT or STOCHASTIC > STOCHASTIC EXIT or CP > BB HIGH or MFI > MFI EXIT)* or 1 of 7 CANDLESTICK PATTERNS shows to SELL\n", "10. BUY when ALL 7 TECHNICAL INDICATORS show to BUY (CP > MA and FAST MA > SLOW MA and MACD > MACD SIGNAL and RSI > RSI ENTRY and STOCHASTIC > STOCHASTIC ENTRY and CP < BB LOW, and MFI > MFI ENTRY)* AND 1 of 5 CANDLESTICK PATTERNS shows to BUY ==> SELL when 1 of 7 TECHNICAL INDICATORS shows to SELL (CP < MA or FAST MA < SLOW MA or MACD < MACD SIGNAL or RSI > RSI EXIT or STOCHASTIC > STOCHASTIC EXIT or CP > BB HIGH or MFI > MFI EXIT)* or 1 of 7 CANDLESTICK PATTERNS shows to SELL\n", "11. BUY when MACD crosses over MACD SIGNAL only when MACD < 0 ==> SELL when MACD crosses under MACD SIGNAL\n", "12. BUY when MACD crosses over MACD SIGNAL only when MACD < 0 and (MA is higher than MA from 2 minutes before and MA from 2 minutes before is higher than MA from 4 minutes before) ==> SELL when (STOCHASTIC is over STOCHASTIC EXIT and RSI over RSI EXIT) or (CP over BB HIGH and MFI over MFI EXIT)\n", "13. BUY when last CLOSE PRICE is higher than the CLOSE PRICE from a minute before ==> SELL when last CLOSE PRICE is lower than the CLOSE PRICE from a minute before\n", "\n", "- and never buy when the time is set to 'buyless' (e.g., first 15 minutes of trading session)\n", "- and always sell when the time is set to 'selltime' (e.g., 5 minutes till the trading session ends)\n", "- and use take profit and stop loss to maximize gains and minimize risks\n", "\n", "\\* '>' here represents the crossing over\n", "\n", "\\* '<' here represents the crossing under" ] }, { "cell_type": "markdown", "id": "dbe78daf", "metadata": {}, "source": [ "# SETTING UP YOUR WORK STATION\n", "\n", "To start working with this notebook, you need Python and Jupyter Notebook.\n", "\n", "To get Python, go to https://www.anaconda.com, download it, and install it.\n", "\n", "After you install Anaconda on your computer, create a new environment in it (with 1 click) and install Jupyter Notebook and CMD.exe Prompt within the environment (with 2 clicks).\n", "\n", "To use the bot you also need, at least, a free account at Alpaca. To get that account go to https://alpaca.markets and sign up to it. At the moment, if you only want to use paper trading account, you only need an email address to sign up. \n", "\n", "After you do it, you are ready to start working with this notebook." ] }, { "cell_type": "markdown", "id": "f62d4469", "metadata": {}, "source": [ "# I. THE ONLY THING YOU HAVE TO CHANGE TO MAKE THE BOT WORK\n", "\n", "# INSERT YOUR KEYS TO THE BOT\n", "\n", "These 2 lines of code are the only two lines you have to change to make the bot work. You need to put here your own keys to Alpaca account. At the moment of creating this tutorial, Alpaca is free to use for everyone and with paper account you only need an email address to sign up." ] }, { "cell_type": "code", "execution_count": null, "id": "b1db2714", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot\n", "KEY_ID = \"your own KEY_ID\" #replace it with your own KEY_ID from Alpaca: https://alpaca.markets/\n", "SECRET_KEY = \"your own SECRET_KEY\" #replace it with your own SECRET_KEY from Alpaca" ] }, { "cell_type": "markdown", "id": "18390951", "metadata": {}, "source": [ "# II. THINGS YOU DON'T NEED TO CHANGE, BUT MIGHT TO EASILY MAKE THE BOT BETTER\n", "\n", "## INSTALL (optional) AND IMPORT EXTERNAL TOOLS (LIBRARIES, PACKAGES, AND MODULES)\n", "\n", "## Install and update all the neccessary libraries, packages, modules\n", "\n", "At first, we install all the necessary libraries and packages. \n", "\n", "You may install more of them if you need, but the ones you find here are enough to run the bot. \n", "\n", "You can skip it if you already have them installed or you can upgrade or downgrade them if necessary." ] }, { "cell_type": "code", "execution_count": null, "id": "6acffeeb", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "#You need to run it only once when you create new environment\n", "#install and upgrade TA-Lib library\n", "\n", "#1. On Windows and if you are using Anaconda, \n", "#open Anaconda Prompt and\n", "#write in Anaconda Prompt: conda install -c conda-forge ta-lib\n", "\n", "#2. If it doesn't work or if you work on Linux or Mac you may unahsh pip line and check this way \n", "#!pip install TA-Lib --upgrade\n", "\n", "#3. You could also check this site to learn how else you could do install it\n", "#https://pypi.org/project/TA-Lib/" ] }, { "cell_type": "code", "execution_count": null, "id": "572c802b", "metadata": { "scrolled": true }, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "#You need to run it only once when you create new environment\n", "#install and upgrade all the libraries, packages, and modules which you don't have\n", "\n", "!pip install alpaca-trade-api --upgrade\n", "#https://pypi.org/project/alpaca-trade-api/\n", "\n", "!pip install numpy==1.22.4\n", "#https://pypi.org/project/numpy/\n", "\n", "!pip install pandas --upgrade\n", "#https://pypi.org/project/pandas/\n", "\n", "!pip install ta --upgrade\n", "#https://pypi.org/project/ta/\n", "\n", "!pip install vectorbt --upgrade\n", "#https://pypi.org/project/vectorbt/\n", "\n", "!pip install yfinance --upgrade\n", "#https://pypi.org/project/yfinance/" ] }, { "cell_type": "markdown", "id": "d4acd736", "metadata": {}, "source": [ "## Import all the neccessary libraries, packages, modules" ] }, { "cell_type": "code", "execution_count": null, "id": "e0028d43", "metadata": { "scrolled": true }, "outputs": [], "source": [ "#SuperAI Trading Bot - 2. mandatory cell to run\n", "#import all you need\n", "\n", "import alpaca_trade_api as tradeapi\n", "from alpaca_trade_api.rest import TimeFrame\n", "import datetime\n", "from datetime import timedelta\n", "import math\n", "import numpy as np\n", "import pandas as pd\n", "import sys\n", "import ta\n", "import talib as ta_lib\n", "import time\n", "import vectorbt as vbt\n", "import warnings\n", "warnings.filterwarnings('ignore')\n", "\n", "print(\"Python version: {}\".format(sys.version))\n", "print(\"alpaca trade api version: {}\".format(tradeapi.__version__))\n", "print(\"numpy version: {}\".format(np.__version__))\n", "print(\"pandas version: {}\".format(pd.__version__))\n", "print(\"ta_lib version: {}\".format(ta_lib.__version__))\n", "print(\"vectorbt version: {}\".format(vbt.__version__))" ] }, { "cell_type": "markdown", "id": "aa36286f", "metadata": {}, "source": [ "Check the version of TA library" ] }, { "cell_type": "code", "execution_count": null, "id": "2e64c365", "metadata": {}, "outputs": [], "source": [ "pip show ta" ] }, { "cell_type": "markdown", "id": "a0043fe4", "metadata": {}, "source": [ "## CHOOSE AN ASSET TO TRADE\n", "\n", "You can choose any asset that can be traded with Alpaca API and paste the ticker of the asset in here. " ] }, { "cell_type": "code", "execution_count": null, "id": "7fab380f", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - 3. mandatory cell to run\n", "\n", "(asset, asset_type, rounding) = (\"BTCUSD\", \"crypto\", 0)\n", "\n", "#if you want to trade crypto check: https://alpaca.markets/support/what-cryptocurrencies-does-alpaca-currently-support/\n", "#rounding declares the no of numbers after comma for orders\n", "#read more about minimum qty and qty increment at https://alpaca.markets/docs/trading/crypto-trading/\n", "\n", "#(asset, asset_type, data_source) = (\"AAPL\", \"stock\", \"Yahoo\") #(\"AAPL\", \"stock\", \"Alpaca\")\n", "\n", "#if you want to trade stocks replace it with the ticker of the company you prefer: https://www.nyse.com/listings_directory/stock\n", "#you can also use \"Alpaca\" as a data_source\n", "#Alpaca gives you free access to more historical data, but in a free plan doesn't allow you to access data from last 15 minutes\n", "#Yahoo gives you access to data from last 15 minutes, but gives you only 7 days of historical data with 1-min interval at a time\n", "#from last month" ] }, { "cell_type": "markdown", "id": "0f5a82df", "metadata": {}, "source": [ "## SHAPE THE BRAIN OF THE BOT\n", "\n", "Here you can declare which technical indicators and candlestick patterns you want to use as signals to buy and sell stocks and how the signals should be created (what should the logic for buying and selling be). \n", "\n", "You have 6 indicators from 4 categories to use: \n", "1. TREND INDICATORS: EMA (Exponential Moving Average), MACD (Moving Average Convergence Divergence)\n", "2. MOMENTUM INDICATORS: RSI (Relative Strength Index), Stoch (Stochastic) \n", "3. VOLATILITY: BB (Bollinger Bands)\n", "4. VOLUME: MFI (Money Flow Index)\n", "\n", "You have 8 candlestick patterns from 3 categories to use:\n", "1. BUY CANDLE PATTERNS: from 1 candle: Hammer, from 3 candles: Morning Star, 3 White Soldiers\n", "2. SELL CANDLE PATTERNS: from 1 candle: Shooting Star, from 3 candles: Evening Star, 3 Black Crows\n", "3. BUY - SELL CANDLE PATTERNS: from 2 candles: Engulfing Bullish / Bearish, from 3 candles: 3 Outside Up / Down\n", "\n", "#### Declare which indicators and how should be used in a function for creating a SuperAI trading signal (buy / sell / do nothing)" ] }, { "attachments": { "crossing.png": { "image/png": "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" } }, "cell_type": "markdown", "id": "393706a2", "metadata": {}, "source": [ "1st Sample Strategy - with moving average: BUY when CLOSE PRICE crosses over MA ==> SELL when CLOSE PRICE crosses under MA\n", "\n", "![crossing.png](attachment:crossing.png)" ] }, { "cell_type": "code", "execution_count": null, "id": "2db7f13e", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - 4. mandatory cell to run\n", "# 1st SAMPLE STRATEGY - WITH MOVING AVERAGE\n", "# BUY WHEN CLOSE PRICE CROSSES OVER THE MOVING AVERAGE \n", "# SELL WHEN CLOSE PRICE CROSSES UNDER THE MOVING AVERAGE\n", "\n", "def create_signal(open_prices, high_prices, low_prices, close_prices, volume,\n", " buylesstime, selltime, #Time to abstain from buying and forced selling\n", " ma, ma_fast, ma_slow, #Moving Average\n", " macd, macd_diff, macd_sign, #Moving Average Convergence Divergence\n", " rsi, rsi_entry, rsi_exit, #Relative Strength Index\n", " stoch, stoch_signal, stoch_entry, stoch_exit, #Stochastic\n", " bb_low, bb_high, #Bollinger Bands\n", " mfi, mfi_entry, mfi_exit, #Money Flow Index\n", " candle_buy_signal_1, candle_buy_signal_2, candle_buy_signal_3, #Candle signals to buy\n", " candle_sell_signal_1, candle_sell_signal_2, candle_sell_signal_3, #Candle signals to sell\n", " candle_buy_sell_signal_1, candle_buy_sell_signal_2): #Candle signals to buy or sell\n", " \n", " \n", " SuperAI_signal_buy = np.where( \n", " (buylesstime != 1) \n", " &\n", " ((close_prices > ma) & (shifted(close_prices, 1) <= shifted(ma, 1)))\n", " , 1, 0) #1 is buy, -1 is sell, 0 is do nothing\n", " SuperAI_signal = np.where( \n", " (selltime == 1)\n", " |\n", " ((close_prices < ma) & (shifted(close_prices, 1) >= shifted(ma, 1)))\n", " , -1, SuperAI_signal_buy) #1 is buy, -1 is sell, 0 is do nothing\n", " \n", " global cs_name\n", " cs_name = '1st Sample Strategy'\n", " \n", " return SuperAI_signal" ] }, { "cell_type": "markdown", "id": "c2d18794", "metadata": {}, "source": [ "## DECLARE PARAMETERS AND FUNCTIONS FOR BACKTESTING AND LIVE TRADING" ] }, { "cell_type": "code", "execution_count": null, "id": "1d3a1f54", "metadata": { "scrolled": true }, "outputs": [], "source": [ "#SuperAI Trading Bot - 5. mandatory cell to run\n", "\n", "# PARAMETERS FOR CONNECTING TO ALPACA\n", "\n", "#The URLs we use here are for paper trading. If you want to use your bot with your live account, you should change these URLs to\n", "#those dedicated to live account at Alpaca. Just remember, that with live account you are using real money, \n", "#so be sure that your bot works as you want it to work. Test your bot before you give it real money to trade.\n", "APCA_API_BASE_URL = \"https://paper-api.alpaca.markets\"\n", "\n", "#Connecting to API\n", "api = tradeapi.REST(KEY_ID, SECRET_KEY, APCA_API_BASE_URL, \"v2\")\n", "\n", "#Keys to use Alpaca with vectorbt backtesting library\n", "vbt.settings.data['alpaca']['key_id'] = KEY_ID\n", "vbt.settings.data['alpaca']['secret_key'] = SECRET_KEY\n", "\n", "\n", "# PARAMETERS USED BY SUPERAI TRADING BOT WITH AND WITHOUT OPTIMIZATION\n", "\n", "funds_percentage = 90 #replace it with the percentage of the amount of money you have to use for trading\n", "\n", "take_profit_percent = 0.5 # 50%\n", "stop_loss_percent = 0.05 # 5%\n", "\n", "#Parameters for live trading (during paper trading take profit and stop loss are always on, but you can change it in the code)\n", "take_profit_automatically = True #change to False if you don't want to use take_profit function during live trading\n", "stop_loss_automatically = True #change to False if you don't want to use stop_loss function during live trading\n", "\n", "#Funds to invest\n", "account = api.get_account()\n", "cash = float(account.cash)\n", "buying_power = float(account.buying_power)\n", "funds = cash * funds_percentage / 100\n", "\n", "#Parameters for downloading the data\n", "data_timeframe = '1m' #replace with preferable time between data: 1m, 5m, 15m, 30m, 1h, 1d\n", "data_limit = None #replace with the limit of the data to download to speed up the process (500, 1000, None)\n", "\n", "crypto_data_timeframe = TimeFrame.Minute\n", "preferred_exchange = \"CBSE\"\n", "\n", "#Basic parameters to use for indicators before/without optimization\n", "ma_window_max = ma_window = ma_timeframe = 28\n", "ma_fast_window_max = ma_fast_window = ma_fast_timeframe = 14 \n", "ma_slow_window_max = ma_slow_window = ma_slow_timeframe = 50\n", "\n", "macd_slow_window_max = macd_slow_window = macd_slow_timeframe = 26\n", "macd_fast_window_max = macd_fast_window = macd_fast_timeframe = 12\n", "macd_sign_window_max = macd_sign_window = macd_signal_timeframe = 9\n", "\n", "rsi_window_max = rsi_window = rsi_timeframe = 14\n", "rsi_entry_max = rsi_entry = rsi_oversold_threshold = 30\n", "rsi_exit_max = rsi_exit = rsi_overbought_threshold = 70\n", "\n", "stoch_window_max = stoch_window = stoch_timeframe = 14\n", "stoch_smooth_window_max = stoch_smooth_window = stoch_smooth_timeframe = 3\n", "stoch_entry_max = stoch_entry = stoch_oversold_threshold = 20\n", "stoch_exit_max = stoch_exit = stoch_overbought_threshold = 80\n", "\n", "bb_window_max = bb_window = bb_timeframe = 10\n", "bb_dev_max = bb_dev = bb_dev = 2\n", "\n", "mfi_window_max = mfi_window = mfi_timeframe = 14\n", "mfi_entry_max = mfi_entry = mfi_oversold_threshold = 20\n", "mfi_exit_max = mfi_exit = mfi_overbought_threshold = 80\n", "\n", "#Parameters to optimize during backtesting\n", "\n", "ma_window_opt = np.arange(14, 30, step=14, dtype=int) #[14, 28]\n", "ma_fast_window_opt = np.arange(14, 22, step=7, dtype=int) #[14, 21]\n", "ma_slow_window_opt = np.arange(30, 51, step=20, dtype=int) #[30, 50]\n", "\n", "macd_slow_window_opt = np.arange(26, 27, step=100, dtype=int) #[26]\n", "macd_fast_window_opt = np.arange(12, 13, step=100, dtype=int) #[12]\n", "macd_sign_window_opt = np.arange(9, 10, step=100, dtype=int) #[9]\n", "\n", "rsi_window_opt = np.arange(14, 22, step=7, dtype=int) #[14, 21]\n", "rsi_entry_opt = np.arange(20, 31, step=10, dtype=int) #[20, 30]\n", "rsi_exit_opt = np.arange(70, 81, step=10, dtype=int) #[70, 80]\n", "\n", "stoch_window_opt = np.arange(14, 15, step=100, dtype=int) #[14]\n", "stoch_smooth_window_opt = np.arange(3, 4, step=100, dtype=int) #[3]\n", "stoch_entry_opt = np.arange(20, 21, step=100, dtype=int) #[20]\n", "stoch_exit_opt = np.arange(80, 81, step=100, dtype=int) #[80]\n", "\n", "bb_window_opt = np.arange(10, 21, step=10, dtype=int) #[10, 20]\n", "bb_dev_opt = np.arange(2, 3, step=100, dtype=int) #[2]\n", "\n", "mfi_window_opt = np.arange(14, 22, step=7, dtype=int) #[14, 21]\n", "mfi_entry_opt = np.arange(10, 21, step=10, dtype=int) #[10, 20]\n", "mfi_exit_opt = np.arange(80, 91, step=10, dtype=int) #[80, 90]\n", "\n", "\n", "# PARAMETERS FOR DECISIONS REGARDING OPTIONS AND TIME OF BACKTESTING AND LIVE TRADING\n", "\n", "optimization = True #True or False\n", "validation = True #True or False\n", "\n", "#Dates to download data for backtesting training phase\n", "data_start = '2022-07-01' #replace with the starting point for collecting data\n", "data_end = '2022-07-31' #replace with the ending point for collecting the data\n", "\n", "#Dates to download data for backtesting validation phase\n", "valid_start = '2022-08-01'\n", "valid_end = '2022-08-15'\n", "\n", "#The function for declaring trading hours\n", "def trading_buy_sell_time():\n", " if asset_type == 'stock':\n", " #more about trading hours at: https://alpaca.markets/docs/trading/orders/#extended-hours-trading\n", " trading_hour_start = \"09:30\"\n", " trading_hour_stop = \"16:00\" \n", " #time when you don't want to buy at the beginning of the day \n", " buyless_time_start_1 = \"09:30\"\n", " buyless_time_end_1 = \"09:45\"\n", " buyless_time_start_2 = \"15:55\"\n", " buyless_time_end_2 = \"16:00\"\n", " #time when you want to sell by the end of the day\n", " selltime_start = \"15:55\"\n", " selltime_end = \"16:00\"\n", "\n", " elif asset_type == 'crypto':\n", " trading_hour_start = \"00:00\"\n", " trading_hour_stop = \"23:59\" \n", " #time when you don't want to buy at the beginning of the day \n", " buyless_time_start_1 = \"23:59\"\n", " buyless_time_end_1 = \"00:01\"\n", " buyless_time_start_2 = \"23:58\"\n", " buyless_time_end_2 = \"23:59\"\n", " #time when you want to sell by the end of the day\n", " selltime_start = \"23:59\"\n", " selltime_end = \"00:00\"\n", " \n", " return (trading_hour_start, trading_hour_stop, \n", " buyless_time_start_1, buyless_time_end_1, buyless_time_start_2, buyless_time_end_2,\n", " selltime_start, selltime_end)\n", "\n", "#DataFrame for testing various strategies\n", "columns = ('Strategy', 'Basic Returns', 'Returns After Optimization', 'Returns From Validation')\n", "strategies = pd.DataFrame([], columns=columns).set_index('Strategy')\n", "strategy_returns = ['0',0,0,0]" ] }, { "cell_type": "markdown", "id": "d2f6b802", "metadata": {}, "source": [ "# III. THINGS YOU DON'T NEED TO CHANGE, BUT MIGHT IF YOU WANT TO MAKE MORE ADVANCED CHANGES TO THE BOT\n", "\n", "## All the other necessary functions and variables of the bot used during backtesting and live paper trading\n", "\n", "There is no need to change them." ] }, { "cell_type": "code", "execution_count": null, "id": "57d6f45f", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - 6. mandatory cell to run\n", "\n", "# 1. ALL THE OTHER NECESSARY FUNCTIONS AND VARIABLES OF THE BOT USED DURING BACKTESTING\n", "\n", "#helper function to shift data in order to test differences between data from x min and data from x-time min\n", "def shifted(data, shift_window):\n", " data_shifted = np.roll(data, shift_window)\n", " if shift_window >= 0:\n", " data_shifted[:shift_window] = np.NaN\n", " elif shift_window < 0:\n", " data_shifted[shift_window:] = np.NaN\n", " return data_shifted\n", "\n", "#preparing data in one function\n", "def prepare_data(start_date, end_date):\n", " data_start = start_date\n", " data_end = end_date\n", " \n", " if asset_type == \"stock\" and data_source == \"Alpaca\":\n", " full_data = vbt.AlpacaData.download(asset, start=data_start, end=data_end, \n", " timeframe=data_timeframe, limit=data_limit).get()\n", " \n", " elif asset_type == \"stock\" and data_source == \"Yahoo\":\n", " try:\n", " full_data = vbt.YFData.download(asset, start = data_start, end= data_end, \n", " interval=data_timeframe).get().drop([\"Dividends\", \"Stock Splits\"], axis=1)\n", " except:\n", " full_data = vbt.AlpacaData.download(asset, start=data_start, end=data_end, \n", " timeframe=data_timeframe, limit=data_limit).get()\n", " print(\"\"\"\\nI tried downloading data with Yahoo, but something went wrong so I downloaded data with Alpaca.\n", " That means than the data might not look the same as the data from Yahoo.\\n\\n\"\"\")\n", " \n", " elif asset_type == \"crypto\":\n", " crypto_data = api.get_crypto_bars(asset, crypto_data_timeframe, start = data_start, end=data_end).df\n", " full_crypto_data = crypto_data[crypto_data['exchange'] == preferred_exchange]\n", " full_data = full_crypto_data.rename(str.capitalize, axis=1).drop([\"Exchange\", \"Trade_count\", \"Vwap\"], axis=1)\n", " \n", " else:\n", " print(\"You have to declare asset type as crypto or stock for me to work properly.\")\n", " \n", " full_data.index = full_data.index.tz_convert('America/New_York')\n", " \n", " (trading_hour_start, trading_hour_stop, \n", " buyless_time_start_1, buyless_time_end_1, buyless_time_start_2, buyless_time_end_2,\n", " selltime_start, selltime_end) = trading_buy_sell_time()\n", " \n", " data = full_data.copy()\n", " data = data.between_time(trading_hour_start, trading_hour_stop)\n", " \n", " not_time_to_buy_1 = data.index.indexer_between_time(buyless_time_start_1, buyless_time_end_1) \n", " not_time_to_buy_2 = data.index.indexer_between_time(buyless_time_start_2, buyless_time_end_2) \n", " not_time_to_buy = np.concatenate((not_time_to_buy_1, not_time_to_buy_2), axis=0)\n", " not_time_to_buy = np.unique(not_time_to_buy)\n", " data[\"NotTimeToBuy\"] = 1\n", " data[\"BuylessTime\"] = data.iloc[not_time_to_buy, 5]\n", " data[\"BuylessTime\"] = np.where(np.isnan(data[\"BuylessTime\"]), 0, data[\"BuylessTime\"])\n", " data = data.drop([\"NotTimeToBuy\"], axis=1)\n", "\n", " time_to_sell = data.index.indexer_between_time(selltime_start, selltime_end) \n", " \n", " data[\"TimeToSell\"] = 1\n", " data[\"SellTime\"] = data.iloc[time_to_sell, 6]\n", " data[\"SellTime\"] = np.where(np.isnan(data[\"SellTime\"]), 0, data[\"SellTime\"])\n", " data = data.drop([\"TimeToSell\"], axis=1)\n", " \n", " open_prices = data[\"Open\"]\n", " high_prices = data[\"High\"]\n", " low_prices = data[\"Low\"]\n", " close_prices = data[\"Close\"]\n", " volume = data[\"Volume\"]\n", " buylesstime = data[\"BuylessTime\"]\n", " selltime = data[\"SellTime\"]\n", " \n", " return open_prices, high_prices, low_prices, close_prices, volume, buylesstime, selltime\n", "\n", "def starting_max_parameters():\n", " #assigning the starting parameters as previously declared\n", " \n", " global ma_window_max, ma_fast_window_max, ma_slow_window_max \n", " global macd_slow_window_max, macd_fast_window_max, macd_sign_window_max\n", " global rsi_window_max, rsi_entry_max, rsi_exit_max \n", " global stoch_window_max, stoch_smooth_window_max, stoch_entry_max, stoch_exit_max\n", " global bb_window_max, bb_dev_max, mfi_window_max\n", " global mfi_entry_max, mfi_exit_max\n", "\n", " ma_window_max = ma_window\n", " ma_fast_window_max = ma_fast_window \n", " ma_slow_window_max = ma_slow_window\n", "\n", " macd_slow_window_max = macd_slow_window\n", " macd_fast_window_max = macd_fast_window\n", " macd_sign_window_max = macd_sign_window\n", " \n", " rsi_window_max = rsi_window\n", " rsi_entry_max = rsi_entry\n", " rsi_exit_max = rsi_exit\n", "\n", " stoch_window_max = stoch_window\n", " stoch_smooth_window_max = stoch_smooth_window\n", " stoch_entry_max = stoch_entry\n", " stoch_exit_max = stoch_exit\n", "\n", " bb_window_max = bb_window\n", " bb_dev_max = bb_dev\n", " \n", " mfi_window_max = mfi_window\n", " mfi_entry_max = mfi_entry\n", " mfi_exit_max = mfi_exit\n", "\n", "# Custom SuperAI Indicator\n", "# Signals Function\n", "def superai_signals (open_prices, high_prices, low_prices, close_prices, volume, buylesstime, selltime,\n", " ma_window = ma_timeframe, \n", " ma_fast_window = ma_fast_timeframe,\n", " ma_slow_window = ma_slow_timeframe,\n", " macd_slow_window = macd_slow_timeframe, \n", " macd_fast_window = macd_fast_timeframe, \n", " macd_sign_window = macd_signal_timeframe,\n", " rsi_window = rsi_timeframe,\n", " rsi_entry = rsi_oversold_threshold, \n", " rsi_exit = rsi_overbought_threshold, \n", " stoch_window = stoch_timeframe,\n", " stoch_smooth_window = stoch_smooth_timeframe,\n", " stoch_entry = stoch_oversold_threshold, \n", " stoch_exit = stoch_overbought_threshold,\n", " bb_window = bb_timeframe,\n", " bb_dev = bb_dev,\n", " mfi_window = mfi_timeframe,\n", " mfi_entry = mfi_oversold_threshold,\n", " mfi_exit = mfi_overbought_threshold):\n", " \n", " rsi = vbt.IndicatorFactory.from_ta('RSIIndicator').run(close_prices, window = rsi_window).rsi.to_numpy()\n", " \n", " stoch = vbt.IndicatorFactory.from_ta('StochasticOscillator').run(\n", " high_prices, low_prices, close_prices, window = stoch_window, smooth_window = stoch_smooth_window).stoch.to_numpy()\n", " stoch_signal = vbt.IndicatorFactory.from_ta('StochasticOscillator').run(\n", " high_prices, low_prices, close_prices, window = stoch_window, \n", " smooth_window = stoch_smooth_window).stoch_signal.to_numpy()\n", " \n", " ma = vbt.IndicatorFactory.from_ta('EMAIndicator').run(close_prices, window = ma_window).ema_indicator.to_numpy()\n", " ma_fast = vbt.IndicatorFactory.from_ta('EMAIndicator').run(close_prices, window = ma_fast_window).ema_indicator.to_numpy()\n", " ma_slow = vbt.IndicatorFactory.from_ta('EMAIndicator').run(close_prices, window = ma_slow_window).ema_indicator.to_numpy()\n", " \n", " macd = vbt.IndicatorFactory.from_ta('MACD').run(\n", " close_prices, window_slow = macd_slow_window, window_fast = macd_fast_window, \n", " window_sign = macd_sign_window).macd.to_numpy()\n", " macd_diff = vbt.IndicatorFactory.from_ta('MACD').run(\n", " close_prices, macd_slow_window, window_fast = macd_fast_window, \n", " window_sign = macd_sign_window).macd_diff.to_numpy()\n", " macd_sign = vbt.IndicatorFactory.from_ta('MACD').run(\n", " close_prices, macd_slow_window, window_fast = macd_fast_window, \n", " window_sign = macd_sign_window).macd_signal.to_numpy()\n", "\n", " bb_low = vbt.IndicatorFactory.from_ta('BollingerBands').run(\n", " close_prices, window = bb_window, window_dev = bb_dev).bollinger_lband.to_numpy()\n", " bb_high = vbt.IndicatorFactory.from_ta('BollingerBands').run(\n", " close_prices, window = bb_window, window_dev = bb_dev).bollinger_hband.to_numpy()\n", " \n", " mfi = vbt.IndicatorFactory.from_ta('MFIIndicator').run(\n", " high_prices, low_prices, close_prices, volume, window = mfi_timeframe).money_flow_index.to_numpy()\n", " \n", " candle_buy_signal_1 = vbt.IndicatorFactory.from_talib('CDLHAMMER').run(\n", " open_prices, high_prices, low_prices, close_prices).integer.to_numpy() # 'Hammer'\n", " candle_buy_signal_2 = vbt.IndicatorFactory.from_talib('CDLMORNINGSTAR').run(\n", " open_prices, high_prices, low_prices, close_prices).integer.to_numpy() # 'Morning star'\n", " candle_buy_signal_3 = vbt.IndicatorFactory.from_talib('CDL3WHITESOLDIERS').run(\n", " open_prices, high_prices, low_prices, close_prices).integer.to_numpy() # 'Three White Soldiers'\n", " candle_sell_signal_1 = vbt.IndicatorFactory.from_talib('CDLSHOOTINGSTAR').run(\n", " open_prices, high_prices, low_prices, close_prices).integer.to_numpy() # 'Shooting star' \n", " candle_sell_signal_2 = vbt.IndicatorFactory.from_talib('CDLEVENINGSTAR').run(\n", " open_prices, high_prices, low_prices, close_prices).integer.to_numpy() # 'Evening star'\n", " candle_sell_signal_3 = vbt.IndicatorFactory.from_talib('CDL3BLACKCROWS').run(\n", " open_prices, high_prices, low_prices, close_prices).integer.to_numpy() # '3 Black Crows'\n", " candle_buy_sell_signal_1 = vbt.IndicatorFactory.from_talib('CDLENGULFING').run(\n", " open_prices, high_prices, low_prices, close_prices).integer.to_numpy() # 'Engulfing: Bullish (buy) / Bearish (sell)'\n", " candle_buy_sell_signal_2 = vbt.IndicatorFactory.from_talib('CDL3OUTSIDE').run(\n", " open_prices, high_prices, low_prices, close_prices).integer.to_numpy() # 'Three Outside: Up (buy) / Down (sell)'\n", " \n", " SuperAI_signal = create_signal(open_prices, high_prices, low_prices, close_prices, volume, \n", " buylesstime, selltime, \n", " ma, ma_fast, ma_slow,\n", " macd, macd_diff, macd_sign,\n", " rsi, rsi_entry, rsi_exit, \n", " stoch, stoch_signal, stoch_entry, stoch_exit,\n", " bb_low, bb_high, \n", " mfi, mfi_entry, mfi_exit,\n", " candle_buy_signal_1, candle_buy_signal_2, candle_buy_signal_3,\n", " candle_sell_signal_1, candle_sell_signal_2, candle_sell_signal_3,\n", " candle_buy_sell_signal_1, candle_buy_sell_signal_2)\n", " return SuperAI_signal\n", "\n", "#Parameters to optimize\n", "parameters_names = [\"ma_window\", \"ma_fast_window\", \"ma_slow_window\", \n", " \"macd_slow_window\", \"macd_fast_window\", \"macd_sign_window\", \n", " \"rsi_window\", \"rsi_entry\", \"rsi_exit\",\n", " \"stoch_window\", \"stoch_smooth_window\", \"stoch_entry\", \"stoch_exit\",\n", " \"bb_window\", \"bb_dev\", \n", " \"mfi_window\", \"mfi_entry\", \"mfi_exit\"]\n", "\n", "#Indicator\n", "SuperAI_Ind = vbt.IndicatorFactory(\n", " class_name = \"SuperAI_Ind\",\n", " short_name = \"SuperInd\",\n", " input_names = [\"open\", \"high\", \"low\", \"close\", \"volume\", \"buylesstime\", \"selltime\"],\n", " param_names = parameters_names,\n", " output_names = [\"output\"]).from_apply_func(superai_signals,\n", " ma_window = ma_timeframe,\n", " ma_fast_window = ma_fast_timeframe,\n", " ma_slow_window = ma_slow_timeframe, \n", " \n", " macd_slow_window = macd_slow_timeframe, \n", " macd_fast_window = macd_fast_timeframe,\n", " macd_sign_window = macd_signal_timeframe,\n", " \n", " rsi_window = rsi_timeframe,\n", " rsi_entry = rsi_oversold_threshold, \n", " rsi_exit = rsi_overbought_threshold,\n", " \n", " stoch_window = stoch_timeframe,\n", " stoch_smooth_window = stoch_smooth_timeframe,\n", " stoch_entry = stoch_oversold_threshold, \n", " stoch_exit = stoch_overbought_threshold,\n", " \n", " bb_window = bb_timeframe,\n", " bb_dev = bb_dev,\n", " \n", " mfi_window = mfi_timeframe,\n", " mfi_entry = mfi_oversold_threshold, \n", " mfi_exit = mfi_overbought_threshold)\n", "\n", "def SuperAI_Backtester():\n", " #BACKTESTING WITH TRAINING AND VALIDATION SET\n", " print(\"\\nI start the backtesting. The declared parameters at the moment are:\\n\")\n", " \n", " #Resetting the parameters to the declared ones\n", " starting_max_parameters()\n", " \n", " global ma_window_max, ma_fast_window_max, ma_slow_window_max \n", " global macd_slow_window_max, macd_fast_window_max, macd_sign_window_max\n", " global rsi_window_max, rsi_entry_max, rsi_exit_max \n", " global stoch_window_max, stoch_smooth_window_max, stoch_entry_max, stoch_exit_max\n", " global bb_window_max, bb_dev_max, mfi_window_max\n", " global mfi_entry_max, mfi_exit_max\n", " \n", " basic_returns = np.NaN\n", " optimized_returns = np.NaN\n", " validated_returns = np.NaN\n", "\n", " print(\"\"\" ma_window_max: {}, ma_fast_window_max: {}, ma_slow_window_max: {}, \n", " macd_slow_window_max: {}, macd_fast_window_max: {}, macd_sign_window_max: {},\n", " rsi_window_max: {}, rsi_entry_max: {}, rsi_exit_max: {}, \n", " stoch_window_max: {}, stoch_smooth_window_max: {}, stoch_entry_max: {}, stoch_exit_max: {},\n", " bb_window_max: {}, bb_dev_max: {}, \n", " mfi_window_max: {}, mfi_entry_max: {}, mfi_exit_max: {}\\n\"\"\".format(\n", " ma_window_max, ma_fast_window_max, ma_slow_window_max, \n", " macd_slow_window_max, macd_fast_window_max, macd_sign_window_max,\n", " rsi_window_max, rsi_entry_max, rsi_exit_max, \n", " stoch_window_max, stoch_smooth_window_max, stoch_entry_max, stoch_exit_max,\n", " bb_window_max, bb_dev_max, mfi_window_max, \n", " mfi_entry_max, mfi_exit_max))\n", "\n", " print(\"\\nI'm downloading the data for {} from {} to {}.\\n\".format(asset, data_start, data_end))\n", " \n", " #Remembering the backtested asset\n", " global backtested_asset\n", " backtested_asset = asset\n", " \n", " #Preparing data\n", " open_prices, high_prices, low_prices, close_prices, volume, buylesstime, selltime = prepare_data(data_start, data_end)\n", "\n", " print(\"I have the data. I start doing the calculations.\\n\")\n", " \n", " #TESTING THE PROTOTYPE\n", " trading_signals = SuperAI_Ind.run(open_prices, high_prices, low_prices, close_prices, volume, buylesstime, selltime,\n", "\n", " ma_window = ma_timeframe,\n", " ma_fast_window = ma_fast_timeframe,\n", " ma_slow_window = ma_slow_timeframe,\n", "\n", " macd_slow_window = macd_slow_timeframe,\n", " macd_fast_window = macd_fast_timeframe,\n", " macd_sign_window = macd_signal_timeframe,\n", "\n", " rsi_window = rsi_timeframe,\n", " rsi_entry = rsi_oversold_threshold,\n", " rsi_exit= rsi_overbought_threshold,\n", "\n", " stoch_window = stoch_timeframe,\n", " stoch_smooth_window = stoch_smooth_timeframe,\n", " stoch_entry = stoch_oversold_threshold, \n", " stoch_exit = stoch_overbought_threshold,\n", "\n", " bb_window = bb_timeframe,\n", " bb_dev = bb_dev,\n", "\n", " mfi_window = mfi_timeframe,\n", " mfi_entry = mfi_oversold_threshold,\n", " mfi_exit= mfi_overbought_threshold,\n", "\n", " param_product = True)\n", "\n", " entries = trading_signals.output == 1.0\n", " exits = trading_signals.output == -1.0\n", "\n", " SuperAI_portfolio = vbt.Portfolio.from_signals(close_prices, \n", " entries, \n", " exits, \n", " init_cash = 100000, \n", " tp_stop = take_profit_percent,\n", " sl_stop = stop_loss_percent,\n", " fees = 0.00)\n", "\n", " returns = SuperAI_portfolio.total_return() * 100\n", " basic_returns = returns\n", " stats = SuperAI_portfolio.stats()\n", " \n", " print(\"I did the backtest with previously declared indicators and parameters.\\n\")\n", " print(\"Returns before optimization: \", returns, \"\\n\")\n", " print(\"Stats before optimization:\")\n", " print(stats, \"\\n\")\n", "\n", " #OPTIMIZING THE BOT WITH A GRID OF DIFFERENT POSSIBILITIES FOR PREFERRED PARAMETER\n", " if optimization == True:\n", " print(\"I start the optimization. The parameters before optimization are:\\n\")\n", " \n", " print(\"\"\" ma_window_max: {}, ma_fast_window_max: {}, ma_slow_window_max: {}, \n", " macd_slow_window_max: {}, macd_fast_window_max: {}, macd_sign_window_max: {},\n", " rsi_window_max: {}, rsi_entry_max: {}, rsi_exit_max: {}, \n", " stoch_window_max: {}, stoch_smooth_window_max: {}, stoch_entry_max: {}, stoch_exit_max: {},\n", " bb_window_max: {}, bb_dev_max: {}, \n", " mfi_window_max: {}, mfi_entry_max: {}, mfi_exit_max: {}\\n\"\"\".format(\n", " ma_window_max, ma_fast_window_max, ma_slow_window_max, \n", " macd_slow_window_max, macd_fast_window_max, macd_sign_window_max,\n", " rsi_window_max, rsi_entry_max, rsi_exit_max, \n", " stoch_window_max, stoch_smooth_window_max, stoch_entry_max, stoch_exit_max,\n", " bb_window_max, bb_dev_max, mfi_window_max, \n", " mfi_entry_max, mfi_exit_max))\n", " \n", " print(\" Now I'm doing the calculations. It may take me some time (it depends on the power of your computer)\\n\\\n", " and the amount of data I have to analyze. So, be patient and relax for now.\\n\")\n", " \n", " trading_signals = SuperAI_Ind.run(open_prices, high_prices, low_prices, close_prices, volume, buylesstime, selltime,\n", "\n", " ma_window = ma_window_opt,\n", " ma_fast_window = ma_fast_window_opt,\n", " ma_slow_window = ma_slow_window_opt,\n", "\n", " macd_slow_window = macd_slow_window_opt,\n", " macd_fast_window = macd_fast_window_opt,\n", " macd_sign_window = macd_sign_window_opt,\n", "\n", " rsi_window = rsi_window_opt,\n", " rsi_entry = rsi_entry_opt,\n", " rsi_exit = rsi_exit_opt,\n", "\n", " stoch_window = stoch_window_opt,\n", " stoch_smooth_window = stoch_smooth_window_opt,\n", " stoch_entry = stoch_entry_opt,\n", " stoch_exit = stoch_exit_opt,\n", "\n", " bb_window = bb_window_opt,\n", " bb_dev = bb_dev_opt,\n", "\n", " mfi_window = mfi_window_opt,\n", " mfi_entry = mfi_entry_opt,\n", " mfi_exit = mfi_exit_opt,\n", "\n", " param_product = True)\n", "\n", " entries = trading_signals.output == 1.0\n", " exits = trading_signals.output == -1.0\n", "\n", " SuperAI_portfolio = vbt.Portfolio.from_signals(close_prices, \n", " entries, \n", " exits, \n", " init_cash = 100000, \n", " tp_stop = take_profit_percent,\n", " sl_stop = stop_loss_percent,\n", " fees = 0.00)\n", "\n", " stats_all = SuperAI_portfolio.stats()\n", "\n", " returns = SuperAI_portfolio.total_return() * 100\n", " \n", " max_dd = SuperAI_portfolio.max_drawdown()\n", "\n", " sharpe_ratio = SuperAI_portfolio.sharpe_ratio(freq='m')\n", "\n", " #APPLYING THE BEST PARAMETERS TO THE MODEL\n", " \n", " (ma_window_max, ma_fast_window_max, ma_slow_window_max, \n", " macd_slow_window_max, macd_fast_window_max, macd_sign_window_max,\n", " rsi_window_max, rsi_entry_max, rsi_exit_max, \n", " stoch_window_max, stoch_smooth_window_max, stoch_entry_max, stoch_exit_max,\n", " bb_window_max, bb_dev_max, mfi_window_max, \n", " mfi_entry_max, mfi_exit_max) = returns.idxmax() #max_dd.idxmax() #sharpe_ratio.idxmax()\n", " \n", " trading_signals = SuperAI_Ind.run(open_prices, high_prices, low_prices, close_prices, volume, buylesstime, selltime,\n", "\n", " ma_window = ma_window_max,\n", " ma_fast_window = ma_fast_window_max,\n", " ma_slow_window = ma_slow_window_max,\n", "\n", " macd_slow_window = macd_slow_window_max,\n", " macd_fast_window = macd_fast_window_max,\n", " macd_sign_window = macd_sign_window_max,\n", "\n", " rsi_window = rsi_window_max,\n", " rsi_entry = rsi_entry_max,\n", " rsi_exit= rsi_exit_max,\n", "\n", " stoch_window = stoch_window_max,\n", " stoch_smooth_window = stoch_smooth_window_max,\n", " stoch_entry = stoch_entry_max, \n", " stoch_exit = stoch_exit_max,\n", "\n", " bb_window = bb_window_max,\n", " bb_dev = bb_dev_max,\n", "\n", " mfi_window = mfi_window_max,\n", " mfi_entry = mfi_entry_max,\n", " mfi_exit= mfi_exit_max,\n", "\n", " param_product = True)\n", "\n", " entries = trading_signals.output == 1.0\n", " exits = trading_signals.output == -1.0\n", "\n", " SuperAI_portfolio = vbt.Portfolio.from_signals(close_prices, \n", " entries, \n", " exits, \n", " init_cash = 100000, \n", " tp_stop = take_profit_percent,\n", " sl_stop = stop_loss_percent,\n", " fees = 0.00)\n", "\n", " opt_returns = SuperAI_portfolio.total_return() * 100\n", " optimized_returns = opt_returns\n", "\n", " opt_stats = SuperAI_portfolio.stats()\n", "\n", " print(\"I optimized the parameters.\")\n", " print(\"The parameters after optimization are:\\n\")\n", " print(\"\"\" ma_window_max: {}, ma_fast_window_max: {}, ma_slow_window_max: {}, \n", " macd_slow_window_max: {}, macd_fast_window_max: {}, macd_sign_window_max: {},\n", " rsi_window_max: {}, rsi_entry_max: {}, rsi_exit_max: {}, \n", " stoch_window_max: {}, stoch_smooth_window_max: {}, stoch_entry_max: {}, stoch_exit_max: {},\n", " bb_window_max: {}, bb_dev_max: {}, \n", " mfi_window_max: {}, mfi_entry_max: {}, mfi_exit_max: {}\\n\"\"\".format(\n", " ma_window_max, ma_fast_window_max, ma_slow_window_max, \n", " macd_slow_window_max, macd_fast_window_max, macd_sign_window_max,\n", " rsi_window_max, rsi_entry_max, rsi_exit_max, \n", " stoch_window_max, stoch_smooth_window_max, stoch_entry_max, stoch_exit_max,\n", " bb_window_max, bb_dev_max, mfi_window_max, \n", " mfi_entry_max, mfi_exit_max))\n", " \n", " print(\"\\nMax returns after optimization: \", opt_returns, \"\\n\")\n", " print(\"Stats after optimization:\")\n", " print(opt_stats, \"\\n\")\n", " else:\n", " print(\"You declared You don't want any optimization. I respect that and I'm not going to do any optimization.\\n\")\n", " \n", " #VALIDATION OF THE MODEL\n", " if validation == True:\n", " print(\"I start the validation. I'm downloading the data for {} from {} to {}.\".format(asset, valid_start, valid_end))\n", " print(\"For previous calculations I used data for {} from {} to {}.\".format(asset, data_start, data_end))\n", " \n", " open_prices, high_prices, low_prices, close_prices, volume, buylesstime, selltime = prepare_data(valid_start, valid_end)\n", "\n", " print(\"I've got the data. I'm starting the calculations.\\n\")\n", " trading_signals = SuperAI_Ind.run(open_prices, high_prices, low_prices, close_prices, volume, buylesstime, selltime,\n", "\n", " ma_window = ma_window_max,\n", " ma_fast_window = ma_fast_window_max,\n", " ma_slow_window = ma_slow_window_max,\n", "\n", " macd_slow_window = macd_slow_window_max,\n", " macd_fast_window = macd_fast_window_max,\n", " macd_sign_window = macd_sign_window_max,\n", "\n", " rsi_window = rsi_window_max,\n", " rsi_entry = rsi_entry_max,\n", " rsi_exit= rsi_exit_max,\n", "\n", " stoch_window = stoch_window_max,\n", " stoch_smooth_window = stoch_smooth_window_max,\n", " stoch_entry = stoch_entry_max, \n", " stoch_exit = stoch_exit_max,\n", "\n", " bb_window = bb_window_max,\n", " bb_dev = bb_dev_max,\n", "\n", " mfi_window = mfi_window_max,\n", " mfi_entry = mfi_entry_max,\n", " mfi_exit= mfi_exit_max,\n", "\n", " param_product = True)\n", "\n", " entries = trading_signals.output == 1.0\n", " exits = trading_signals.output == -1.0\n", "\n", " SuperAI_portfolio = vbt.Portfolio.from_signals(close_prices, \n", " entries, \n", " exits, \n", " init_cash = 100000, \n", " tp_stop = take_profit_percent,\n", " sl_stop = stop_loss_percent,\n", " fees = 0.00)\n", "\n", " val_returns = SuperAI_portfolio.total_return() * 100\n", " validated_returns = val_returns\n", " val_stats = SuperAI_portfolio.stats()\n", "\n", " print(\"I've finished the validation.\\n\")\n", " print(\"Returns from validation: \", val_returns, \"\\n\")\n", " print(\"Stats from validation:\")\n", " print(val_stats, \"\\n\")\n", " \n", " else:\n", " print(\"You declared You don't want to do any validation. Ok, I won't do any.\\n\")\n", " \n", " strategy_returns[0] = cs_name\n", " strategy_returns[1] = basic_returns\n", " strategy_returns[2] = optimized_returns\n", " strategy_returns[3] = validated_returns\n", " strategy_to_df = pd.DataFrame([strategy_returns], columns=columns)\n", " \n", " global strategies\n", " strategies = pd.concat([strategies, strategy_to_df])\n", "\n", " print(\"\"\" Now You have to decide whether we go with this strategy to live paper trading \n", " or you want to try another strategy. Whatever your decision is, I'm here for you.\\n\\n\"\"\") \n", " \n", "\n", "# 2. ALL THE OTHER FUNCTIONS AND VARIABLES OF THE BOT NEEDED FOR LIVE TRADING WITH PAPER TRADING ACCOUNT\n", "#Taking profit\n", "profit_ratio = 100 + (take_profit_percent * 100)\n", "def take_profit(close_price, sell_order_filled):\n", " if take_profit_automatically == True:\n", " try:\n", " position = api.get_position(asset)\n", " aep = float(api.get_position(asset).avg_entry_price)\n", "\n", " if sell_order_filled == False:\n", " if close_price >= aep * profit_ratio / 100:\n", " n_shares = float(position.qty)\n", " api.submit_order(symbol=asset,qty=n_shares,side='sell',type='market',time_in_force='gtc')\n", " print(\"Take profit price is {}% from {:.2f}$ we paid for 1 {} = {:.2f}$. \"\n", " .format(profit_ratio, aep, asset, aep * profit_ratio / 100))\n", " print('The current {:.2f}$ is good enough. We take profit with an order to sell {} shares/coins of {}.'\n", " .format(close_price, n_shares, asset))\n", " else:\n", " print('Take profit price is {}% from the price we used for buying: {:.2f}$ for 1 {} and that is {:.2f}$.'\n", " .format(profit_ratio, aep, asset, aep * profit_ratio / 100))\n", " print('Last close price {:.2f}$ is not enough.'.format(close_price))\n", " except:\n", " pass\n", "\n", " print()\n", " else:\n", " pass\n", " \n", "#Stopping loss\n", "stoploss_ratio = 100 - (stop_loss_percent * 100)\n", "def stop_loss(close_price, sell_order_filled):\n", " if stop_loss_automatically == True:\n", " try:\n", " position = api.get_position(asset)\n", " aep = float(api.get_position(asset).avg_entry_price)\n", "\n", " if sell_order_filled == False:\n", " if close_price < aep * stoploss_ratio / 100:\n", " n_shares = float(position.qty)\n", " api.submit_order(symbol=asset,qty=n_shares,side='sell',type='market',time_in_force='gtc')\n", " print(\"Stop loss price is {}% from {:.2f}$ we paid for 1 {} = {:.2f}$.\"\n", " .format(stoploss_ratio, aep, asset, aep * stoploss_ratio / 100))\n", " print('The current {:.2f}$ is less. We stop loss with an order to sell {} shares/coins of {}.'\n", " .format(close_price, n_shares, asset))\n", " else:\n", " print(\"Stop loss price is {}% from the price we used for buying: {:.2f}$ for 1 {} and that is {:.2f}$.\"\n", " .format(stoploss_ratio, aep, asset, aep * stoploss_ratio / 100))\n", " print(\"Last close price {:.2f}$ is not that low.\".format(close_price))\n", " except:\n", " pass\n", "\n", " print()\n", " else:\n", " pass\n", "\n", "# Caclulating Technical Indicators and Candlestick Patterns Signals\n", "def cal_tech_ind(open_prices, high_prices, low_prices, close_prices, volume, buylesstime, selltime):\n", " #CALCULATING TECHNICAL INDICATORS SIGNALS \n", " close_price = close_prices[-1]\n", " #Calculating MA Signals\n", " try:\n", " ma = ta.trend.ema_indicator(close_prices, window = ma_window_max)\n", " ma = np.round(ma, 2)\n", " ma_last = float(ma.iloc[-1])\n", "\n", " ma_fast = ta.trend.ema_indicator(close_prices, window = ma_fast_window_max)\n", " ma_fast = np.round(ma_fast, 2)\n", " ma_fast_last = float(ma_fast.iloc[-1])\n", "\n", " ma_slow = ta.trend.ema_indicator(close_prices, window = ma_slow_window_max)\n", " ma_slow = np.round(ma_slow, 2)\n", " ma_slow_last = float(ma_slow.iloc[-1])\n", "\n", " print(\"Last MA is: {:.3f}. Last Fast MA is: {:.3f}. Last Slow MA is: {:.3f}.\\n\".format(ma_last, \n", " ma_fast_last, ma_slow_last))\n", " except:\n", " print (\"MA signal doesn't work.\\n\")\n", " \n", " #Calculating MACD Signal\n", " try:\n", " macd = ta.trend.macd(close_prices, window_slow = macd_slow_window_max, window_fast = macd_fast_window_max)\n", " macd = np.round(macd, 2)\n", " macd_last = float(macd.iloc[-1])\n", " \n", " macd_diff = ta.trend.macd_diff(close_prices, window_slow = macd_slow_window_max, \n", " window_fast = macd_fast_window_max, window_sign = macd_sign_window_max)\n", " macd_diff = np.round(macd_diff, 2)\n", " macd_diff_last = float(macd_diff.iloc[-1])\n", " \n", " macd_sign = ta.trend.macd_signal(close_prices, window_slow = macd_slow_window_max, \n", " window_fast = macd_fast_window_max, window_sign = macd_sign_window_max)\n", " macd_sign = np.round(macd_sign, 2)\n", " macd_sign_last = float(macd_sign.iloc[-1])\n", "\n", " print(\"Last MACD is: {:.3f}. Last MACD_DIFF is: {:.3f}. Last MACD_SIGNAL is: {:.3f}.\\n\".format(macd_last, \n", " macd_diff_last, macd_sign_last))\n", " except:\n", " print (\"MACD signal doesn't work.\\n\")\n", " \n", " #Calculating RSI Signal\n", " try:\n", " rsi = ta.momentum.rsi(close_prices, window = rsi_window_max)\n", " rsi = np.round(rsi, 2)\n", " rsi_last = rsi.iloc[-1]\n", " rsi_entry = rsi_entry_max\n", " rsi_exit = rsi_exit_max\n", " \n", " print(\"Last RSI is {:.3f}. RSI thresholds are: {:.2f} - {:.2f}.\\n\".format(rsi_last, rsi_entry, rsi_exit))\n", " except:\n", " print(\"RSI signal doesn't work.\\n\")\n", "\n", " #Calculating Stochastic Signal\n", " try:\n", " stoch = ta.momentum.stoch(high_prices, low_prices, close_prices, \n", " window = stoch_window_max, smooth_window = stoch_smooth_window_max)\n", " stoch = np.round(stoch, 2)\n", " stoch_last = stoch.iloc[-1]\n", " \n", " stoch_sign = ta.momentum.stoch_signal(high_prices, low_prices, close_prices, \n", " window = stoch_window_max, smooth_window = stoch_smooth_window_max)\n", " stoch = np.round(stoch_sign, 2)\n", " stoch_sign_last = stoch_sign.iloc[-1]\n", " \n", " stoch_entry = stoch_entry_max\n", " stoch_exit = stoch_exit_max\n", " \n", " print(\"Last Stochastic is {:.3f}. Stochastic thresholds are: {:.2f} - {:.2f}.\\n\".format(\n", " stoch_last, stoch_entry, stoch_exit))\n", " print(\"Last Stochastic Signal is {:.3f}. Stochastic thresholds are: {:.2f} - {:.2f}.\\n\".format(\n", " stoch_sign_last, stoch_entry, stoch_exit))\n", " except:\n", " print(\"Stochastic signal doesn't work.\\n\")\n", " \n", " #Calculating Bollinger Bands Signal\n", " try:\n", " bb_low = ta.volatility.bollinger_lband(close_prices, window=bb_window_max, window_dev = bb_dev_max)\n", " bb_low = np.round(bb_low, 2)\n", " bb_high = ta.volatility.bollinger_hband(close_prices, window=bb_window_max, window_dev = bb_dev_max)\n", " bb_high = np.round(bb_high, 2)\n", " \n", " bb_low_last = float(bb_low.iloc[-1])\n", " bb_high_last = float(bb_high.iloc[-1])\n", "\n", " print(\"Last price is: {}$. Bollinger Bands are: Lower: {:.3f}, Upper: {:.3f}.\\n\".format(close_price, \n", " bb_low_last, bb_high_last))\n", " except:\n", " print (\"Bollinger Bands signal doesn't work.\\n\")\n", " \n", " #Calculating MFI Signal\n", " try:\n", " mfi = ta.volume.money_flow_index(high_prices, low_prices, close_prices, volume, window = mfi_window_max)\n", " mfi = np.round(mfi, 2)\n", " mfi_last = mfi.iloc[-1]\n", " mfi_entry = mfi_entry_max\n", " mfi_exit = mfi_exit_max\n", "\n", " print(\"Last MFI is {:.3f}. MFI thresholds are: {:.2f} - {:.2f}.\\n\".format(mfi_last, mfi_entry, mfi_exit))\n", " except:\n", " print(\"MFI signal doesn't work.\\n\")\n", " \n", " return (ma, ma_fast, ma_slow, \n", " macd, macd_diff, macd_sign,\n", " rsi, rsi_entry, rsi_exit, \n", " stoch, stoch_sign, stoch_entry, stoch_exit, \n", " bb_low, bb_high, \n", " mfi, mfi_entry, mfi_exit)\n", "\n", "#SuperAI Trading Bot\n", "def cal_can_pat(open_prices, high_prices, low_prices, close_prices, volume, buylesstime, selltime):\n", " #CALCULATING CANDLESTICK PATTERNS AND SIGNALS \n", " #Hammer\n", " candle_buy_signal_1 = ta_lib.CDLHAMMER(open_prices, high_prices, low_prices, close_prices)\n", " last_candle_buy_signal_1 = candle_buy_signal_1.iloc[-1]\n", " print(\"Last Candle Buy Signal 1: {}.\".format(last_candle_buy_signal_1))\n", "\n", " #Morning Star\n", " candle_buy_signal_2 = ta_lib.CDLMORNINGSTAR(open_prices, high_prices, low_prices, close_prices)\n", " last_candle_buy_signal_2 = candle_buy_signal_2.iloc[-1]\n", " print(\"Last Candle Buy Signal 2: {}.\".format(last_candle_buy_signal_2))\n", " \n", " #Three White Soldiers\n", " candle_buy_signal_3 = ta_lib.CDL3WHITESOLDIERS(open_prices, high_prices, low_prices, close_prices)\n", " last_candle_buy_signal_3 = candle_buy_signal_3.iloc[-1]\n", " print(\"Last Candle Buy Signal 3: {}.\".format(last_candle_buy_signal_3))\n", " \n", " #Shooting Star\n", " candle_sell_signal_1 = ta_lib.CDLSHOOTINGSTAR(open_prices, high_prices, low_prices, close_prices)\n", " last_candle_sell_signal_1 = candle_sell_signal_1.iloc[-1]\n", " print(\"Last Candle Sell Signal 1: {}.\".format(last_candle_sell_signal_1))\n", " \n", " #Evening Star\n", " candle_sell_signal_2 = ta_lib.CDLEVENINGSTAR(open_prices, high_prices, low_prices, close_prices)\n", " last_candle_sell_signal_2 = candle_sell_signal_2.iloc[-1]\n", " print(\"Last Candle Sell Signal 2: {}.\".format(last_candle_sell_signal_2))\n", " \n", " #3 Black Crows\n", " candle_sell_signal_3 = ta_lib.CDL3BLACKCROWS(open_prices, high_prices, low_prices, close_prices)\n", " last_candle_sell_signal_3 = candle_sell_signal_3.iloc[-1]\n", " print(\"Last Candle Sell Signal 3: {}.\".format(last_candle_sell_signal_3))\n", " \n", " #Engulfing (Bullish (buy) / Bearish (Sell))\n", " candle_buy_sell_signal_1 = ta_lib.CDLENGULFING(open_prices, high_prices, low_prices, close_prices)\n", " last_candle_buy_sell_signal_1 = candle_buy_sell_signal_1.iloc[-1]\n", " print(\"Last Candle Buy Sell Signal 1: {}.\".format(last_candle_buy_sell_signal_1))\n", " \n", " #Three Outside: Up (buy) / Down (sell)\n", " candle_buy_sell_signal_2 = ta_lib.CDL3OUTSIDE(open_prices, high_prices, low_prices, close_prices)\n", " last_candle_buy_sell_signal_2 = candle_buy_sell_signal_2.iloc[-1]\n", " print(\"Last Candle Buy Sell Signal 2: {}.\".format(last_candle_buy_sell_signal_2))\n", " \n", " return (candle_buy_signal_1, candle_buy_signal_2, candle_buy_signal_3,\n", " candle_sell_signal_1, candle_sell_signal_2, candle_sell_signal_3,\n", " candle_buy_sell_signal_1, candle_buy_sell_signal_2)\n", "\n", "# Check if market is open\n", "def check_if_market_open():\n", " if api.get_clock().is_open == False:\n", " print(\"The market is closed at the moment.\")\n", " print(\"Time to open is around: {:.0f} minutes. So I'll stop working for now. Hope you don't mind.\"\n", " .format((api.get_clock().next_open.timestamp()- api.get_clock().timestamp.timestamp())/60))\n", " sys.exit(\"I'm out. Turn me back on when it's time. Yours, SuperAI trader.\")\n", " else:\n", " pass\n", "\n", "#Buyless time\n", "def buyless_time(time_now):\n", " (trading_hour_start, trading_hour_stop, \n", " buyless_time_start_1, buyless_time_end_1, buyless_time_start_2, buyless_time_end_2,\n", " selltime_start, selltime_end) = trading_buy_sell_time()\n", "\n", " buyless1_start = datetime.time(int(buyless_time_start_1[:2]), int(buyless_time_start_1[3:]))\n", " buyless1_end = datetime.time(int(buyless_time_end_1[:2]), int(buyless_time_end_1[3:]))\n", " buyless2_start = datetime.time(int(buyless_time_start_2[:2]), int(buyless_time_start_2[3:]))\n", " buyless2_end = datetime.time(int(buyless_time_end_2[:2]), int(buyless_time_end_2[3:]))\n", "\n", " buylesstime = (buyless1_start < time_now < buyless1_end) | (buyless2_start < time_now < buyless2_end) \n", " print('is it buyless time? ', buylesstime)\n", " return buylesstime\n", "\n", "#Sell time\n", "def sell_time(time_now):\n", " (trading_hour_start, trading_hour_stop, \n", " buyless_time_start_1, buyless_time_end_1, buyless_time_start_2, buyless_time_end_2,\n", " selltime_start, selltime_end) = trading_buy_sell_time()\n", "\n", " sell_time_start = datetime.time(int(selltime_start[:2]), int(selltime_start[3:]))\n", " sell_time_end = datetime.time(int(selltime_end[:2]), int(selltime_end[3:])) \n", "\n", " selltime = (sell_time_start < time_now < sell_time_end) \n", " print('is it sell time? ', selltime)\n", " return selltime\n", "\n", "#Waiting for a bar to close\n", "#check for more: https://alpaca.markets/learn/code-cryptocurrency-live-trading-bot-python-alpaca/\n", "def wait_for_bar_to_close():\n", " time_now = datetime.datetime.now()\n", " next_min = time_now.replace(second=5, microsecond=0) + timedelta(minutes=1)\n", " pause = math.ceil((next_min - time_now).seconds)\n", " print(\"I'll wait {} seconds for the bar to close.\".format(pause))\n", " print(\"\\n* * * * * * * * * * * * * * * * * * * * * * * * *\\n\")\n", " \n", " return pause\n", "\n", "# Function to run after starting the bot (on_open function) \n", "def on_open():\n", " print(\"\\nI'm connected to Alpaca API and ready to work. I'm starting to watch the prices.\\n\") \n", " cash = float(api.get_account().cash)\n", " print(\"We have {:.2f}$ cash.\".format(cash))\n", " \n", " try:\n", " position = api.get_position(asset)\n", " n_shares = float(position.qty)\n", " print(\"We have {} shares/coins of {}.\\n\".format(n_shares, asset))\n", " except:\n", " print(\"We don't have any shares/coins of {} at the moment.\\n\".format(asset))\n", "\n", " funds = cash * funds_percentage / 100\n", " print(\"Funds we will use for trading: {:.2f}$.\\n\".format(funds))\n", " print(\"I will be trading {}.\\n\".format(asset))\n", " try:\n", " print(\"The last backtest I did was for {}.\\n\".format(backtested_asset))\n", " except:\n", " print(\"I didn't do any backtesting yet.\\n\")\n", " \n", " global trading_hour_start, trading_hour_stop\n", " global buyless_time_start_1, buyless_time_end_1, buyless_time_start_2, buyless_time_end_2\n", " global selltime_start, selltime_end\n", " \n", " (trading_hour_start, trading_hour_stop, \n", " buyless_time_start_1, buyless_time_end_1, buyless_time_start_2, buyless_time_end_2,\n", " selltime_start, selltime_end) = trading_buy_sell_time()\n", " \n", " print(\"\"\" I will be trading between {} and {}. \n", " I won't be buying between {} and {} and between {} and {}.\n", " I will sell the shares/coins of {} when it's between {} and {} no matter the trading signals.\\n\"\"\".format(\n", " trading_hour_start, trading_hour_stop, \n", " buyless_time_start_1, buyless_time_end_1, buyless_time_start_2, buyless_time_end_2, asset,\n", " selltime_start, selltime_end, \"\\n\")) \n", " \n", " if take_profit_automatically:\n", " print(\"Take profit is set to +{}% from the average entry price.\".format(take_profit_percent*100))\n", " print(\"I will be trading when the technical indicators and candlestick patterns say so, but also\")\n", " print(\"if entry price is e.g. 100$ I'll automatically sell when last close price is more than 100$+{}%*100$={:.2f}$\"\n", " .format(take_profit_percent * 100, 100*profit_ratio/100))\n", " else:\n", " print(\"Take profit automatically is turned off.\")\n", " print(\"I will use technical indicators and candlestick patterns to get as much profit as I can.\")\n", " \n", " if stop_loss_automatically:\n", " print(\"\\nStop loss is set to -{}% from the average entry price.\".format(stop_loss_percent*100))\n", " print(\"I will be trading when the technical indicators and candlestick patterns say so, but also\")\n", " print(\"if entry price is e.g. 100$ I'll automatically sell when last close price is less than 100$-{}%*100$={:.2f}$\"\n", " .format(stop_loss_percent * 100, 100*stoploss_ratio/100))\n", " else:\n", " print(\"\\nStop loss automatically is turned off.\")\n", " print(\"I will use technical indicators and candlestick patterns so I don't lose money.\")\n", " \n", " print(\"\\nSo, here we go. Wish me luck.\\n\")\n", " print(\"* * * * * * * * * * * * * * * * * * * * * * * * *\\n\")\n", " \n", " if asset_type == \"stock\":\n", " check_if_market_open()\n", " \n", "# Function to run after every message from Alpaca (on_message function)\n", "def on_message():\n", " nyc_datetime = api.get_clock().timestamp.tz_convert('America/New_York')\n", " print(\"New York time:\", str(nyc_datetime)[:16])\n", " \n", " open_prices, high_prices, low_prices, close_prices, volume, buylesstime, selltime = prepare_data(\n", " str(datetime.date.today() - datetime.timedelta(days = 2)), \n", " str(datetime.date.today() + datetime.timedelta(days = 2)))\n", " close_price = close_prices[-1]\n", " \n", " print(\"Close price of {}: {:.2f}$\\n\".format(asset, close_price))\n", " \n", " try:\n", " position = api.get_position(asset)\n", " n_shares = float(position.qty)\n", " print(\"We have {} shares/coins of {}.\\n\".format(n_shares, asset))\n", " except:\n", " print(\"We don't have any shares/coins of {} at the moment.\\n\".format(asset))\n", "\n", " cash = float(api.get_account().cash)\n", " print(\"We have {:.2f}$ cash.\".format(cash))\n", " funds = cash * funds_percentage / 100\n", " print(\"Funds we will use for trading: {:.2f}$.\\n\".format(funds))\n", "\n", " #CALCULATING TECHNICAL INDICATORS SIGNALS\n", " (ma, ma_fast, ma_slow, macd, macd_diff, macd_sign, rsi, rsi_entry, rsi_exit, \n", " stoch, stoch_sign, stoch_entry, stoch_exit, \n", " bb_low, bb_high, mfi, mfi_entry, mfi_exit) = cal_tech_ind(\n", " open_prices, high_prices, low_prices, close_prices, volume, \n", " buylesstime, selltime)\n", "\n", " #CALCULATING CANDLESTICK PATTERNS AND SIGNALS\n", " (candle_buy_signal_1, candle_buy_signal_2, candle_buy_signal_3,\n", " candle_sell_signal_1, candle_sell_signal_2, candle_sell_signal_3,\n", " candle_buy_sell_signal_1, candle_buy_sell_signal_2) = cal_can_pat(\n", " open_prices, high_prices, low_prices, close_prices, volume, \n", " buylesstime, selltime)\n", " \n", " #Calculate final trade signal\n", " try:\n", " final_trade_signals = create_signal(open_prices, high_prices, low_prices, close_prices, volume,\n", " buylesstime, selltime, \n", " ma, ma_fast, ma_slow, \n", " macd, macd_diff, macd_sign,\n", " rsi, rsi_entry, rsi_exit, \n", " stoch, stoch_sign, stoch_entry, stoch_exit, \n", " bb_low, bb_high, \n", " mfi, mfi_entry, mfi_exit,\n", " candle_buy_signal_1, candle_buy_signal_2, candle_buy_signal_3,\n", " candle_sell_signal_1, candle_sell_signal_2, candle_sell_signal_3,\n", " candle_buy_sell_signal_1, candle_buy_sell_signal_2)\n", "\n", " final_trade_signal = final_trade_signals[-1]\n", " if final_trade_signal == 0:\n", " print(\"\\nFinal trade signal is: DO NOTHING\\n\")\n", " elif final_trade_signal == 1:\n", " print(\"\\nFinal trade signal is: BUY\\n\")\n", " elif final_trade_signal == -1:\n", " print(\"\\nFinal trade signal is: SELL\\n\") \n", " except:\n", " print(\"\\nFinal trade signal doesn't work.\\n\")\n", " final_trade_signal = False\n", "\n", " #Execute action after recieving the final trade signal: submitting an order\n", " sell_order_filled = False\n", " if final_trade_signal == 1: #\"buy\":\n", " try:\n", " api.get_position(asset)\n", " print(\"We hit the threshold to buy, but we already have some shares/coins, so we won't buy more.\\n\")\n", " except:\n", " n_shares = np.round(funds // close_price)\n", " if asset_type == 'crypto':\n", " #an overcomplicated way to round down the number of coins to buy to the declared number of places after comma\n", " n_shares = funds//close_price + float((str((funds / close_price)-(funds//close_price))[:(2+rounding)]))\n", " api.submit_order(symbol=asset,qty=n_shares,side=\"buy\",type=\"market\",time_in_force=\"gtc\")\n", " print('We submitted the order to buy {} {} shares/coins.'.format(n_shares, asset))\n", "\n", " try:\n", " position = api.get_position(asset)\n", " aep = float(api.get_position(asset).avg_entry_price)\n", " print(\"The last close price was {}. We bought {} shares/coins of {} for the price of: {}$ for 1 {}.\\n\".format(\n", " close_price, n_shares, asset, aep, asset))\n", " except:\n", " pass \n", " \n", " elif final_trade_signal == -1: #\"sell\":\n", " try:\n", " position = api.get_position(asset)\n", " n_shares = float(position.qty)\n", " api.submit_order(symbol=asset,qty=n_shares,side='sell',type='market',time_in_force='gtc')\n", " sell_order_filled = True\n", " print('We submitted an order to sell {} {} shares/coins.'.format(n_shares, asset))\n", " except:\n", " print(\"We hit the threshold to sell, but we don't have anything to sell. Next time maybe.\\n\")\n", "\n", " else:\n", " print(\"The signal was inconclusive - probably indicators showed us we should wait, so we wait.\\n\")\n", " \n", " #Hand-made take profit\n", " take_profit(close_price, sell_order_filled)\n", "\n", " #Hand-made stop loss\n", " stop_loss(close_price, sell_order_filled)\n", "\n", " print(\"\\n* * * * * * * * * * * * * * * * * * * * * * * * *\\n\")\n", " \n", " if asset_type == \"stock\":\n", " check_if_market_open()\n", " \n", "# Function to run the bot until break or until the market is closed\n", "def SuperAI_Trading_Bot():\n", " on_open()\n", " time.sleep(wait_for_bar_to_close())\n", " \n", " while True:\n", " on_message()\n", " time.sleep(wait_for_bar_to_close())\n", " \n", " print(\"You've interrupted me. That's it than. I hope I did good. Till the next time.\")" ] }, { "cell_type": "markdown", "id": "f936433c", "metadata": {}, "source": [ "And now we have all we need. Now we can run the bot.\n", "\n", "So, here we go!" ] }, { "cell_type": "markdown", "id": "aaf6ad00", "metadata": {}, "source": [ "# HERE WE START RUNNING THE BOT!" ] }, { "cell_type": "markdown", "id": "cbfae93d", "metadata": {}, "source": [ "## DO SOME BACKTESTING\n", "- with 1 line of code if you want to backtest with the asset you've chosen previously\n", "- with 2 lines of code if you want to change the asset to backtest" ] }, { "cell_type": "code", "execution_count": null, "id": "0f7785c9", "metadata": { "scrolled": true }, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "\n", "#the asset was declared at the beginning of the program, but you can change it here if you want\n", "\n", "#(asset, asset_type, rounding) = (\"BTCUSD\", \"crypto\", 0)\n", "#(asset, asset_type, data_source) = (\"AAPL\", \"stock\", \"Yahoo\")\n", "\n", "SuperAI_Backtester()" ] }, { "cell_type": "markdown", "id": "5e7cbb55", "metadata": {}, "source": [ "## START LIVE TRADING WITH PAPER TRADING ACCOUNT\n", "\n", "## Run the bot to trade with crypto (e.g. BTCUSD) or stock (e.g. AAPL)\n", "- with 1 line of code if you want to trade the asset you've chosen previously\n", "- with 2 lines of code if you want to change the asset to trade\n", "\n", "If you want to trade crypto, you have to choose one that Alpaca supports at the moment: https://alpaca.markets/support/what-cryptocurrencies-does-alpaca-currently-support/\n", "\n", "You should also check the minimum quantity you can trade. \n", "\n", "If you want to trade stocks you may choose ticker of the company you prefer: https://www.nyse.com/listings_directory/stock\n", "\n", "Your data_source can be 'Alpaca' or 'Yahoo', just know that:\n", "- Alpaca gives you free access to more historical data, but in a free plan doesn't allow you to access data from last 15 minutes\n", "- Yahoo gives you access to data from last 15 minutes, but gives you only 7 days of historical data with 1-min interval at a time." ] }, { "cell_type": "code", "execution_count": null, "id": "ef9a3243", "metadata": { "scrolled": true }, "outputs": [], "source": [ "#SuperAI Trading Bot - 7. mandatory cell to run\n", "\n", "#the asset was declared at the beginning of the program, but you can change it here if you want\n", "#(asset, asset_type, rounding) = (\"BTCUSD\", \"crypto\", 0)\n", "#(asset, asset_type, data_source) = (\"AAPL\", \"stock\", \"Yahoo\")\n", "\n", "SuperAI_Trading_Bot()" ] }, { "cell_type": "markdown", "id": "65bbbe71", "metadata": {}, "source": [ "And that's it. Now we can start testing different strategies." ] }, { "cell_type": "markdown", "id": "f8d84874", "metadata": {}, "source": [ "# TESTING THE 13 STRATEGIES" ] }, { "cell_type": "markdown", "id": "24879a45", "metadata": {}, "source": [ "## The 13 tested trading strategies are:\n", "1. BUY when CLOSE PRICE crosses over MA ==> SELL when CLOSE PRICE crosses under MA\n", "2. BUY when FAST MA crosses over SLOW MA ==> SELL when FAST MA crosses under SLOW MA\n", "3. BUY when MACD crosses over MACD SIGNAL ==> SELL when MACD crosses under MACD SIGNAL\n", "4. BUY when RSI crosses under RSI OVERSOLD THRESHOLD ==> SELL when RSI crosses over RSI OVERBOUGHT THRESHOLD\n", "5. BUY when STOCHASTIC crosses under STOCHASTIC OVERSOLD THRESHOLD ==> SELL when STOCHASTIC crosses over STOCHASTIC OVERBOUGHT THRESHOLD\n", "6. BUY when CLOSE PRICE crosses under LOWER BOLLINGER BAND ==> SELL when CLOSE PRICE crosses over HIGHER BOLLINGER BAND\n", "7. BUY when MFI crosses under MFI ENTRY THRESHOLD ==> SELL when MFI crosses over MFI EXIT THRESHOLD\n", "8. BUY when at least 1 of 5 CANDLESTICK PATTERNS shows to BUY ==> SELL when at least 1 of 5 CANDLESTICK PATTERNS shows to SELL \n", "9. BUY when 1 of 7 TECHNICAL INDICATORS shows to BUY (CP > MA or FAST MA > SLOW MA or MACD > MACD SIGNAL or RSI > RSI ENTRY or STOCHASTIC > STOCHASTIC ENTRY or CP < BB LOW or MFI > MFI ENTRY)* AND 1 of 5 CANDLESTICK PATTERNS shows to BUY ==> SELL when 1 of 7 TECHNICAL INDICATORS shows to SELL (CP < MA or FAST MA < SLOW MA or MACD < MACD SIGNAL or RSI > RSI EXIT or STOCHASTIC > STOCHASTIC EXIT or CP > BB HIGH or MFI > MFI EXIT)* or 1 of 7 CANDLESTICK PATTERNS shows to SELL\n", "10. BUY when ALL 7 TECHNICAL INDICATORS show to BUY (CP > MA and FAST MA > SLOW MA and MACD > MACD SIGNAL and RSI > RSI ENTRY and STOCHASTIC > STOCHASTIC ENTRY and CP < BB LOW, and MFI > MFI ENTRY)* AND 1 of 5 CANDLESTICK PATTERNS shows to BUY ==> SELL when 1 of 7 TECHNICAL INDICATORS shows to SELL (CP < MA or FAST MA < SLOW MA or MACD < MACD SIGNAL or RSI > RSI EXIT or STOCHASTIC > STOCHASTIC EXIT or CP > BB HIGH or MFI > MFI EXIT)* or 1 of 7 CANDLESTICK PATTERNS shows to SELL\n", "11. BUY when MACD crosses over MACD SIGNAL only when MACD < 0 ==> SELL when MACD crosses under MACD SIGNAL\n", "12. BUY when MACD crosses over MACD SIGNAL only when MACD < 0 and (MA is higher than MA from 2 minutes before and MA from 2 minutes before is higher than MA from 4 minutes before) ==> SELL when (STOCHASTIC is over STOCHASTIC EXIT and RSI over RSI EXIT) or (CP over BB HIGH and MFI over MFI EXIT)\n", "13. BUY when last CLOSE PRICE is higher than the CLOSE PRICE from a minute before ==> SELL when last CLOSE PRICE is lower than the CLOSE PRICE from a minute before\n", "\n", "- and never buy when the time is set to 'buyless' (e.g., first 15 minutes of trading session)\n", "- and always sell when the time is set to 'selltime' (e.g., 5 minutes till the trading session ends)\n", "- and use take profit and stop loss to maximize gains and minimize risks\n", "\n", "\\* '>' here represents the crossing over\n", "\n", "\\* '<' here represents the crossing under" ] }, { "cell_type": "code", "execution_count": null, "id": "a8c7674a", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "# the same variables that were previously declared, copied here for convenience, \n", "# so we don't have to go to the beginning of the program every time we want to change them\n", "\n", "(asset, asset_type, data_source) = (\"AAPL\", \"stock\", \"Yahoo\")\n", "#(asset, asset_type, rounding) = (\"BTCUSD\", \"crypto\", 0)\n", "\n", "optimization = False\n", "validation = True\n", "\n", "(data_start, data_end) = ('2022-07-01', '2022-07-31')\n", "(valid_start, valid_end) = ('2022-08-01', '2022-08-15')" ] }, { "cell_type": "code", "execution_count": null, "id": "e3f0dce1", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "#DataFrame for testing various strategies\n", "\n", "strategies" ] }, { "cell_type": "markdown", "id": "28a30c55", "metadata": {}, "source": [ "## 1. TRADING STRATEGY\n", "### BUY when CLOSE PRICE crosses over MA \n", "### ==> SELL when CLOSE PRICE crosses under MA\n", "\n", "- and never buy when the time is set to 'buyless' (e.g., first 15 minutes of trading session)\n", "- and always sell when the time is set to 'selltime' (e.g., 5 minutes till the trading session ends)\n", "- and use take profit and stop loss to maximize gains and minimize risks" ] }, { "attachments": { "crossing.png": { "image/png": "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" } }, "cell_type": "markdown", "id": "d5adb79e", "metadata": {}, "source": [ "![crossing.png](attachment:crossing.png)" ] }, { "cell_type": "code", "execution_count": null, "id": "4e76ad55", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "# 1. STRATEGY\n", "# BUY when CLOSE PRICE crosses over MA ==> SELL when CLOSE PRICE crosses under MA\n", "\n", "def create_signal(open_prices, high_prices, low_prices, close_prices, volume,\n", " buylesstime, selltime, #Time to abstain from buying and forced selling\n", " ma, ma_fast, ma_slow, #Moving Average\n", " macd, macd_diff, macd_sign, #Moving Average Convergence Divergence\n", " rsi, rsi_entry, rsi_exit, #Relative Strength Index\n", " stoch, stoch_signal, stoch_entry, stoch_exit, #Stochastic\n", " bb_low, bb_high, #Bollinger Bands\n", " mfi, mfi_entry, mfi_exit, #Money Flow Index\n", " candle_buy_signal_1, candle_buy_signal_2, candle_buy_signal_3, #Candle signals to buy\n", " candle_sell_signal_1, candle_sell_signal_2, candle_sell_signal_3, #Candle signals to sell\n", " candle_buy_sell_signal_1, candle_buy_sell_signal_2): #Candle signals to buy or sell\n", " \n", " \n", " SuperAI_signal_buy = np.where( \n", " (buylesstime != 1) \n", " &\n", " ((close_prices > ma) & (shifted(close_prices, 1) <= shifted(ma, 1)))\n", " , 1, 0) #1 is buy, -1 is sell, 0 is do nothing\n", " SuperAI_signal = np.where( \n", " (selltime == 1)\n", " |\n", " ((close_prices < ma) & (shifted(close_prices, 1) >= shifted(ma, 1)))\n", " , -1, SuperAI_signal_buy) #1 is buy, -1 is sell, 0 is do nothing\n", " \n", " global cs_name\n", " cs_name = 'Strategy 1 with Close Prices crossing Moving Average'\n", " \n", " return SuperAI_signal" ] }, { "cell_type": "code", "execution_count": null, "id": "c0929cd0", "metadata": { "scrolled": true }, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "\n", "SuperAI_Backtester()" ] }, { "cell_type": "markdown", "id": "f4f54930", "metadata": {}, "source": [ "## 2. TRADING STRATEGY\n", "### BUY when FAST MA crosses over SLOW MA \n", "### ==> SELL when FAST MA crosses under SLOW MA\n", "\n", "- and never buy when the time is set to 'buyless' (e.g., first 15 minutes of trading session)\n", "- and always sell when the time is set to 'selltime' (e.g., 5 minutes till the trading session ends)\n", "- and use take profit and stop loss to maximize gains and minimize risks" ] }, { "cell_type": "code", "execution_count": null, "id": "a0117227", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "# 2. STRATEGY\n", "# BUY when FAST MA crosses over SLOW MA ==> SELL when FAST MA crosses under SLOW MA\n", "\n", "def create_signal(open_prices, high_prices, low_prices, close_prices, volume,\n", " buylesstime, selltime, #Time to abstain from buying and forced selling\n", " ma, ma_fast, ma_slow, #Moving Average\n", " macd, macd_diff, macd_sign, #Moving Average Convergence Divergence\n", " rsi, rsi_entry, rsi_exit, #Relative Strength Index\n", " stoch, stoch_signal, stoch_entry, stoch_exit, #Stochastic\n", " bb_low, bb_high, #Bollinger Bands\n", " mfi, mfi_entry, mfi_exit, #Money Flow Index\n", " candle_buy_signal_1, candle_buy_signal_2, candle_buy_signal_3, #Candle signals to buy\n", " candle_sell_signal_1, candle_sell_signal_2, candle_sell_signal_3, #Candle signals to sell\n", " candle_buy_sell_signal_1, candle_buy_sell_signal_2): #Candle signals to buy or sell\n", " \n", " \n", " SuperAI_signal_buy = np.where( \n", " (buylesstime != 1) \n", " &\n", " ((ma_fast > ma_slow) & (shifted(ma_fast, 1) <= shifted(ma_slow, 1)))\n", " , 1, 0) #1 is buy, -1 is sell, 0 is do nothing\n", " SuperAI_signal = np.where( \n", " (selltime == 1)\n", " |\n", " ((ma_fast < ma_slow) & (shifted(ma_fast, 1) >= shifted(ma_slow, 1)))\n", " , -1, SuperAI_signal_buy) #1 is buy, -1 is sell, 0 is do nothing\n", " \n", " global cs_name\n", " cs_name = 'Strategy 2 with Fast MA crossing Slow MA'\n", " \n", " return SuperAI_signal" ] }, { "cell_type": "code", "execution_count": null, "id": "5eb2de1c", "metadata": { "scrolled": true }, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "\n", "SuperAI_Backtester()" ] }, { "cell_type": "markdown", "id": "a2cf95ea", "metadata": {}, "source": [ "## 3. TRADING STRATEGY\n", "### BUY when MACD crosses over MACD SIGNAL \n", "### ==> SELL when MACD crosses under MACD SIGNAL\n", "\n", "- and never buy when the time is set to 'buyless' (e.g., first 15 minutes of trading session)\n", "- and always sell when the time is set to 'selltime' (e.g., 5 minutes till the trading session ends)\n", "- and use take profit and stop loss to maximize gains and minimize risks" ] }, { "cell_type": "code", "execution_count": null, "id": "54664f99", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "# 3. STRATEGY\n", "# BUY when MACD crosses over MACD SIGNAL ==> SELL when MACD crosses under MACD SIGNAL\n", "\n", "def create_signal(open_prices, high_prices, low_prices, close_prices, volume,\n", " buylesstime, selltime, #Time to abstain from buying and forced selling\n", " ma, ma_fast, ma_slow, #Moving Average\n", " macd, macd_diff, macd_sign, #Moving Average Convergence Divergence\n", " rsi, rsi_entry, rsi_exit, #Relative Strength Index\n", " stoch, stoch_signal, stoch_entry, stoch_exit, #Stochastic\n", " bb_low, bb_high, #Bollinger Bands\n", " mfi, mfi_entry, mfi_exit, #Money Flow Index\n", " candle_buy_signal_1, candle_buy_signal_2, candle_buy_signal_3, #Candle signals to buy\n", " candle_sell_signal_1, candle_sell_signal_2, candle_sell_signal_3, #Candle signals to sell\n", " candle_buy_sell_signal_1, candle_buy_sell_signal_2): #Candle signals to buy or sell\n", " \n", " \n", " SuperAI_signal_buy = np.where( \n", " (buylesstime != 1) \n", " &\n", " ((macd > macd_sign) & (shifted(macd, 1) <= shifted(macd_sign, 1)))\n", " , 1, 0) #1 is buy, -1 is sell, 0 is do nothing\n", " SuperAI_signal = np.where( \n", " (selltime == 1)\n", " |\n", " ((macd < macd_sign) & (shifted(macd, 1) >= shifted(macd_sign, 1)))\n", " , -1, SuperAI_signal_buy) #1 is buy, -1 is sell, 0 is do nothing\n", " \n", " global cs_name\n", " cs_name = 'Strategy 3 with MACD crossing MACD Signal'\n", " \n", " return SuperAI_signal" ] }, { "cell_type": "code", "execution_count": null, "id": "93e7540a", "metadata": { "scrolled": true }, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "\n", "SuperAI_Backtester()" ] }, { "cell_type": "markdown", "id": "6c2ba4b1", "metadata": {}, "source": [ "## 4. TRADING STRATEGY\n", "### BUY when RSI crosses under RSI OVERSOLD THRESHOLD \n", "### ==> SELL when RSI crosses over RSI OVERBOUGHT THRESHOLD\n", "\n", "- and never buy when the time is set to 'buyless' (e.g., first 15 minutes of trading session)\n", "- and always sell when the time is set to 'selltime' (e.g., 5 minutes till the trading session ends)\n", "- and use take profit and stop loss to maximize gains and minimize risks" ] }, { "cell_type": "code", "execution_count": null, "id": "3eb3b3fd", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "# 4. STRATEGY\n", "# BUY when RSI crosses under RSI OVERSOLD THRESHOLD ==> SELL when RSI crosses over RSI OVERBOUGHT THRESHOLD\n", "\n", "def create_signal(open_prices, high_prices, low_prices, close_prices, volume,\n", " buylesstime, selltime, #Time to abstain from buying and forced selling\n", " ma, ma_fast, ma_slow, #Moving Average\n", " macd, macd_diff, macd_sign, #Moving Average Convergence Divergence\n", " rsi, rsi_entry, rsi_exit, #Relative Strength Index\n", " stoch, stoch_signal, stoch_entry, stoch_exit, #Stochastic\n", " bb_low, bb_high, #Bollinger Bands\n", " mfi, mfi_entry, mfi_exit, #Money Flow Index\n", " candle_buy_signal_1, candle_buy_signal_2, candle_buy_signal_3, #Candle signals to buy\n", " candle_sell_signal_1, candle_sell_signal_2, candle_sell_signal_3, #Candle signals to sell\n", " candle_buy_sell_signal_1, candle_buy_sell_signal_2): #Candle signals to buy or sell\n", " \n", " \n", " SuperAI_signal_buy = np.where( \n", " (buylesstime != 1) \n", " &\n", " ((rsi < rsi_entry) & (shifted(rsi, 1) >= rsi_entry))\n", " , 1, 0) #1 is buy, -1 is sell, 0 is do nothing\n", " SuperAI_signal = np.where( \n", " (selltime == 1)\n", " |\n", " ((rsi > rsi_exit) & (shifted(rsi, 1) <= rsi_exit))\n", " , -1, SuperAI_signal_buy) #1 is buy, -1 is sell, 0 is do nothing\n", " \n", " global cs_name\n", " cs_name = 'Strategy 4 with RSI crossing oversold / overbought thresholds'\n", " \n", " return SuperAI_signal" ] }, { "cell_type": "code", "execution_count": null, "id": "8bfbee99", "metadata": { "scrolled": true }, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "\n", "SuperAI_Backtester()" ] }, { "cell_type": "markdown", "id": "5c8fe0e7", "metadata": {}, "source": [ "## 5. TRADING STRATEGY\n", "### BUY when STOCHASTIC crosses under STOCHASTIC OVERSOLD THRESHOLD \n", "### ==> SELL when STOCHASTIC crosses over STOCHASTIC OVERBOUGHT THRESHOLD\n", "\n", "- and never buy when the time is set to 'buyless' (e.g., first 15 minutes of trading session)\n", "- and always sell when the time is set to 'selltime' (e.g., 5 minutes till the trading session ends)\n", "- and use take profit and stop loss to maximize gains and minimize risks" ] }, { "cell_type": "code", "execution_count": null, "id": "04a60ab9", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "# 5. STRATEGY\n", "# BUY when STOCHASTIC crosses under STOCHASTIC OVERSOLD THRESHOLD \n", "# ==> SELL when STOCHASTIC crosses over STOCHASTIC OVERBOUGHT THRESHOLD\n", "\n", "def create_signal(open_prices, high_prices, low_prices, close_prices, volume,\n", " buylesstime, selltime, #Time to abstain from buying and forced selling\n", " ma, ma_fast, ma_slow, #Moving Average\n", " macd, macd_diff, macd_sign, #Moving Average Convergence Divergence\n", " rsi, rsi_entry, rsi_exit, #Relative Strength Index\n", " stoch, stoch_signal, stoch_entry, stoch_exit, #Stochastic\n", " bb_low, bb_high, #Bollinger Bands\n", " mfi, mfi_entry, mfi_exit, #Money Flow Index\n", " candle_buy_signal_1, candle_buy_signal_2, candle_buy_signal_3, #Candle signals to buy\n", " candle_sell_signal_1, candle_sell_signal_2, candle_sell_signal_3, #Candle signals to sell\n", " candle_buy_sell_signal_1, candle_buy_sell_signal_2): #Candle signals to buy or sell\n", " \n", " \n", " SuperAI_signal_buy = np.where( \n", " (buylesstime != 1) \n", " &\n", " ((stoch < stoch_entry) & (shifted(stoch, 1) >= stoch_entry))\n", " , 1, 0) #1 is buy, -1 is sell, 0 is do nothing\n", " SuperAI_signal = np.where( \n", " (selltime == 1)\n", " |\n", " ((stoch > stoch_exit) & (shifted(stoch, 1) <= stoch_exit))\n", " , -1, SuperAI_signal_buy) #1 is buy, -1 is sell, 0 is do nothing\n", " \n", " global cs_name\n", " cs_name = 'Strategy 5 with Stochastic crossing oversold / overbought thresholds'\n", " \n", " return SuperAI_signal" ] }, { "cell_type": "code", "execution_count": null, "id": "da865d7d", "metadata": { "scrolled": true }, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "\n", "SuperAI_Backtester()" ] }, { "cell_type": "markdown", "id": "4cdc2572", "metadata": {}, "source": [ "## 6. TRADING STRATEGY\n", "### BUY when CLOSE PRICE crosses under LOWER BOLLINGER BAND \n", "### ==> SELL when CLOSE PRICE crosses over HIGHER BOLLINGER BAND\n", "\n", "- and never buy when the time is set to 'buyless' (e.g., first 15 minutes of trading session)\n", "- and always sell when the time is set to 'selltime' (e.g., 5 minutes till the trading session ends)\n", "- and use take profit and stop loss to maximize gains and minimize risks" ] }, { "cell_type": "code", "execution_count": null, "id": "cd751ffb", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "# 6. STRATEGY\n", "# BUY when CLOSE PRICE crosses under LOWER BOLLINGER BAND ==> SELL when CLOSE PRICE crosses over HIGHER BOLLINGER BAND\n", "\n", "def create_signal(open_prices, high_prices, low_prices, close_prices, volume,\n", " buylesstime, selltime, #Time to abstain from buying and forced selling\n", " ma, ma_fast, ma_slow, #Moving Average\n", " macd, macd_diff, macd_sign, #Moving Average Convergence Divergence\n", " rsi, rsi_entry, rsi_exit, #Relative Strength Index\n", " stoch, stoch_signal, stoch_entry, stoch_exit, #Stochastic\n", " bb_low, bb_high, #Bollinger Bands\n", " mfi, mfi_entry, mfi_exit, #Money Flow Index\n", " candle_buy_signal_1, candle_buy_signal_2, candle_buy_signal_3, #Candle signals to buy\n", " candle_sell_signal_1, candle_sell_signal_2, candle_sell_signal_3, #Candle signals to sell\n", " candle_buy_sell_signal_1, candle_buy_sell_signal_2): #Candle signals to buy or sell\n", " \n", " \n", " SuperAI_signal_buy = np.where( \n", " (buylesstime != 1) \n", " &\n", " ((close_prices < bb_low) & (shifted(close_prices, 1) >= shifted(bb_low, 1)))\n", " , 1, 0) #1 is buy, -1 is sell, 0 is do nothing\n", " SuperAI_signal = np.where( \n", " (selltime == 1)\n", " |\n", " ((close_prices > bb_high) & (shifted(close_prices, 1) <= shifted(bb_high, 1)))\n", " , -1, SuperAI_signal_buy) #1 is buy, -1 is sell, 0 is do nothing\n", " \n", " global cs_name\n", " cs_name = 'Strategy 6 with Close Prices crossing Bollinger Bands'\n", " \n", " return SuperAI_signal" ] }, { "cell_type": "code", "execution_count": null, "id": "c2aa9f44", "metadata": { "scrolled": true }, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "\n", "SuperAI_Backtester()" ] }, { "cell_type": "markdown", "id": "c7b7fc4d", "metadata": {}, "source": [ "## 7. TRADING STRATEGY\n", "### BUY when MFI crosses under MFI ENTRY THRESHOLD \n", "### ==> SELL when MFI crosses over MFI EXIT THRESHOLD\n", "\n", "- and never buy when the time is set to 'buyless' (e.g., first 15 minutes of trading session)\n", "- and always sell when the time is set to 'selltime' (e.g., 5 minutes till the trading session ends)\n", "- and use take profit and stop loss to maximize gains and minimize risks" ] }, { "cell_type": "code", "execution_count": null, "id": "cb2f1722", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "# 7. STRATEGY\n", "# BUY when MFI crosses under MFI ENTRY THRESHOLD ==> SELL when MFI crosses over MFI EXIT THRESHOLD\n", "\n", "def create_signal(open_prices, high_prices, low_prices, close_prices, volume,\n", " buylesstime, selltime, #Time to abstain from buying and forced selling\n", " ma, ma_fast, ma_slow, #Moving Average\n", " macd, macd_diff, macd_sign, #Moving Average Convergence Divergence\n", " rsi, rsi_entry, rsi_exit, #Relative Strength Index\n", " stoch, stoch_signal, stoch_entry, stoch_exit, #Stochastic\n", " bb_low, bb_high, #Bollinger Bands\n", " mfi, mfi_entry, mfi_exit, #Money Flow Index\n", " candle_buy_signal_1, candle_buy_signal_2, candle_buy_signal_3, #Candle signals to buy\n", " candle_sell_signal_1, candle_sell_signal_2, candle_sell_signal_3, #Candle signals to sell\n", " candle_buy_sell_signal_1, candle_buy_sell_signal_2): #Candle signals to buy or sell\n", " \n", " \n", " SuperAI_signal_buy = np.where( \n", " (buylesstime != 1) \n", " &\n", " ((mfi < mfi_entry) & (shifted(mfi, 1) >= mfi_entry))\n", " , 1, 0) #1 is buy, -1 is sell, 0 is do nothing\n", " SuperAI_signal = np.where( \n", " (selltime == 1)\n", " |\n", " ((mfi > mfi_exit) & (shifted(mfi, 1) <= mfi_exit))\n", " , -1, SuperAI_signal_buy) #1 is buy, -1 is sell, 0 is do nothing\n", " \n", " global cs_name\n", " cs_name = 'Strategy 7 with MFI crossing entry / exit thresholds'\n", " \n", " return SuperAI_signal" ] }, { "cell_type": "code", "execution_count": null, "id": "1e34dfcd", "metadata": { "scrolled": true }, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "\n", "SuperAI_Backtester()" ] }, { "cell_type": "markdown", "id": "37af1ef1", "metadata": {}, "source": [ "## 8. TRADING STRATEGY\n", "### BUY when at least 1 of 5 CANDLESTICK PATTERNS shows to BUY \n", "### ==> SELL when at least 1 of 5 CANDLESTICK PATTERNS shows to SELL \n", "\n", "- and never buy when the time is set to 'buyless' (e.g., first 15 minutes of trading session)\n", "- and always sell when the time is set to 'selltime' (e.g., 5 minutes till the trading session ends)\n", "- and use take profit and stop loss to maximize gains and minimize risks" ] }, { "cell_type": "code", "execution_count": null, "id": "df0db9e3", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "# 8. STRATEGY\n", "# BUY when at least 1 of 5 CANDLESTICK PATTERNS shows to BUY ==> SELL when at least 1 of 5 CANDLESTICK PATTERNS shows to SELL\n", "\n", "def create_signal(open_prices, high_prices, low_prices, close_prices, volume,\n", " buylesstime, selltime, #Time to abstain from buying and forced selling\n", " ma, ma_fast, ma_slow, #Moving Average\n", " macd, macd_diff, macd_sign, #Moving Average Convergence Divergence\n", " rsi, rsi_entry, rsi_exit, #Relative Strength Index\n", " stoch, stoch_signal, stoch_entry, stoch_exit, #Stochastic\n", " bb_low, bb_high, #Bollinger Bands\n", " mfi, mfi_entry, mfi_exit, #Money Flow Index\n", " candle_buy_signal_1, candle_buy_signal_2, candle_buy_signal_3, #Candle signals to buy\n", " candle_sell_signal_1, candle_sell_signal_2, candle_sell_signal_3, #Candle signals to sell\n", " candle_buy_sell_signal_1, candle_buy_sell_signal_2): #Candle signals to buy or sell\n", " \n", " \n", " SuperAI_signal_buy = np.where( \n", " (buylesstime != 1) \n", " &\n", " ((candle_buy_signal_1 > 0) | (candle_buy_signal_2 > 0) | (candle_buy_signal_3 > 0)\n", " | (candle_buy_sell_signal_1 > 0) | (candle_buy_sell_signal_2 > 0))\n", " , 1, 0) #1 is buy, -1 is sell, 0 is do nothing\n", " SuperAI_signal = np.where( \n", " (selltime == 1)\n", " |\n", " ((candle_sell_signal_1 < 0) | (candle_sell_signal_2 < 0) | (candle_buy_signal_3 < 0)\n", " | (candle_buy_sell_signal_1 < 0) | (candle_buy_sell_signal_2 < 0))\n", " , -1, SuperAI_signal_buy) #1 is buy, -1 is sell, 0 is do nothing\n", " \n", " global cs_name\n", " cs_name = 'Strategy 8 with Candlestick Patterns'\n", " \n", " return SuperAI_signal" ] }, { "cell_type": "code", "execution_count": null, "id": "183c6541", "metadata": { "scrolled": true }, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "\n", "SuperAI_Backtester()" ] }, { "cell_type": "markdown", "id": "58e866d5", "metadata": {}, "source": [ "## 9. TRADING STRATEGY\n", "### BUY when 1 of 7 TECHNICAL INDICATORS shows to BUY (CP > MA or FAST MA > SLOW MA or MACD > MACD SIGNAL or RSI > RSI ENTRY or STOCHASTIC > STOCHASTIC ENTRY or CP < BB LOW or MFI > MFI ENTRY)* AND 1 of 5 CANDLESTICK PATTERNS shows to BUY \n", "### ==> SELL when 1 of 7 TECHNICAL INDICATORS shows to SELL (CP < MA or FAST MA < SLOW MA or MACD < MACD SIGNAL or RSI > RSI EXIT or STOCHASTIC > STOCHASTIC EXIT or CP > BB HIGH or MFI > MFI EXIT)* or 1 of 7 CANDLESTICK PATTERNS shows to SELL\n", "\n", "- and never buy when the time is set to 'buyless' (e.g., first 15 minutes of trading session)\n", "- and always sell when the time is set to 'selltime' (e.g., 5 minutes till the trading session ends)\n", "- and use take profit and stop loss to maximize gains and minimize risks\n", "\n", "\\* '>' here represents the crossing over\n", "\n", "\\* '<' here represents the crossing under" ] }, { "cell_type": "code", "execution_count": null, "id": "1a8c58af", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "# 9. STRATEGY\n", "# BUY when 1 of 7 TECHNICAL INDICATORS shows to BUY (CP > MA or FAST MA > SLOW MA or MACD > MACD SIGNAL or RSI > RSI ENTRY \n", "# or STOCHASTIC > STOCHASTIC ENTRY or CP < BB LOW or MFI > MFI ENTRY)* AND 1 of 5 CANDLESTICK PATTERNS shows to BUY \n", "# ==> SELL when 1 of 7 TECHNICAL INDICATORS shows to SELL (CP < MA or FAST MA < SLOW MA or MACD < MACD SIGNAL or RSI > RSI EXIT \n", "# or STOCHASTIC > STOCHASTIC EXIT or CP > BB HIGH or MFI > MFI EXIT)* or 1 of 7 CANDLESTICK PATTERNS shows to SELL\n", "\n", "def create_signal(open_prices, high_prices, low_prices, close_prices, volume,\n", " buylesstime, selltime, #Time to abstain from buying and forced selling\n", " ma, ma_fast, ma_slow, #Moving Average\n", " macd, macd_diff, macd_sign, #Moving Average Convergence Divergence\n", " rsi, rsi_entry, rsi_exit, #Relative Strength Index\n", " stoch, stoch_signal, stoch_entry, stoch_exit, #Stochastic\n", " bb_low, bb_high, #Bollinger Bands\n", " mfi, mfi_entry, mfi_exit, #Money Flow Index\n", " candle_buy_signal_1, candle_buy_signal_2, candle_buy_signal_3, #Candle signals to buy\n", " candle_sell_signal_1, candle_sell_signal_2, candle_sell_signal_3, #Candle signals to sell\n", " candle_buy_sell_signal_1, candle_buy_sell_signal_2): #Candle signals to buy or sell\n", " \n", " \n", " SuperAI_signal_buy = np.where( \n", " (buylesstime != 1) \n", " &\n", " (\n", " (\n", " ((close_prices > ma) & (shifted(close_prices, 1) <= shifted(ma, 1)))\n", " |\n", " ((ma_fast > ma_slow) & (shifted(ma_fast, 1) <= shifted(ma_slow, 1)))\n", " |\n", " ((macd > macd_sign) & (shifted(macd, 1) <= shifted(macd_sign, 1)))\n", " |\n", " ((rsi < rsi_entry) & (shifted(rsi, 1) >= rsi_entry))\n", " |\n", " ((stoch < stoch_entry) & (shifted(stoch, 1) >= stoch_entry))\n", " |\n", " ((close_prices < bb_low) & (shifted(close_prices, 1) >= shifted(bb_low, 1)))\n", " |\n", " ((mfi < mfi_entry) & (shifted(mfi, 1) >= mfi_entry))\n", " )\n", " & \n", " ((candle_buy_signal_1 > 0) | (candle_buy_signal_2 > 0) | (candle_buy_signal_3 > 0)\n", " | (candle_buy_sell_signal_1 > 0) | (candle_buy_sell_signal_2 > 0))\n", " )\n", " , 1, 0) #1 is buy, -1 is sell, 0 is do nothing\n", " SuperAI_signal = np.where( \n", " (selltime == 1)\n", " |\n", " (\n", " ((close_prices < ma) & (shifted(close_prices, 1) >= shifted(ma, 1)))\n", " |\n", " ((ma_fast < ma_slow) & (shifted(ma_fast, 1) >= shifted(ma_slow, 1)))\n", " |\n", " ((macd < macd_sign) & (shifted(macd, 1) >= shifted(macd_sign, 1)))\n", " |\n", " ((rsi > rsi_exit) & (shifted(rsi, 1) <= rsi_exit))\n", " |\n", " ((stoch > stoch_exit) & (shifted(stoch, 1) <= stoch_exit))\n", " |\n", " ((close_prices > bb_high) & (shifted(close_prices, 1) <= shifted(bb_high, 1)))\n", " |\n", " ((mfi > mfi_exit) & (shifted(mfi, 1) <= mfi_exit))\n", " )\n", " |\n", " ((candle_sell_signal_1 < 0) | (candle_sell_signal_2 < 0) | (candle_buy_signal_3 < 0)\n", " | (candle_buy_sell_signal_1 < 0) | (candle_buy_sell_signal_2 < 0))\n", " , -1, SuperAI_signal_buy) #1 is buy, -1 is sell, 0 is do nothing\n", " \n", " global cs_name\n", " cs_name = 'Strategy 9 with at least 1 Technical Indicator and Candlestick Patterns'\n", " \n", " return SuperAI_signal" ] }, { "cell_type": "code", "execution_count": null, "id": "308d4e6c", "metadata": { "scrolled": true }, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "\n", "SuperAI_Backtester()" ] }, { "cell_type": "markdown", "id": "50c1374d", "metadata": {}, "source": [ "## 10. TRADING STRATEGY\n", "### BUY when ALL 7 TECHNICAL INDICATORS show to BUY (CP > MA and FAST MA > SLOW MA and MACD > MACD SIGNAL and RSI > RSI ENTRY and STOCHASTIC > STOCHASTIC ENTRY and CP < BB LOW, and MFI > MFI ENTRY)* AND 1 of 5 CANDLESTICK PATTERNS shows to BUY \n", "### ==> SELL when 1 of 7 TECHNICAL INDICATORS shows to SELL (CP < MA or FAST MA < SLOW MA or MACD < MACD SIGNAL or RSI > RSI EXIT or STOCHASTIC > STOCHASTIC EXIT or CP > BB HIGH or MFI > MFI EXIT)* or 1 of 7 CANDLESTICK PATTERNS shows to SELL\n", "\n", "- and never buy when the time is set to 'buyless' (e.g., first 15 minutes of trading session)\n", "- and always sell when the time is set to 'selltime' (e.g., 5 minutes till the trading session ends)\n", "- and use take profit and stop loss to maximize gains and minimize risks\n", "\n", "\\* '>' here represents the crossing over\n", "\n", "\\* '<' here represents the crossing under" ] }, { "cell_type": "code", "execution_count": null, "id": "ff5fc8f6", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "# 10. STRATEGY\n", "# BUY when ALL 7 TECHNICAL INDICATORS show to BUY (CP > MA and FAST MA > SLOW MA and MACD > MACD SIGNAL and RSI > RSI ENTRY \n", "# and STOCHASTIC > STOCHASTIC ENTRY and CP < BB LOW, and MFI > MFI ENTRY)* AND 1 of 5 CANDLESTICK PATTERNS shows to BUY \n", "# ==> SELL when 1 of 7 TECHNICAL INDICATORS shows to SELL (CP < MA or FAST MA < SLOW MA or MACD < MACD SIGNAL or RSI > RSI EXIT \n", "# or STOCHASTIC > STOCHASTIC EXIT or CP > BB HIGH or MFI > MFI EXIT)* or 1 of 7 CANDLESTICK PATTERNS shows to SELL\n", "\n", "def create_signal(open_prices, high_prices, low_prices, close_prices, volume,\n", " buylesstime, selltime, #Time to abstain from buying and forced selling\n", " ma, ma_fast, ma_slow, #Moving Average\n", " macd, macd_diff, macd_sign, #Moving Average Convergence Divergence\n", " rsi, rsi_entry, rsi_exit, #Relative Strength Index\n", " stoch, stoch_signal, stoch_entry, stoch_exit, #Stochastic\n", " bb_low, bb_high, #Bollinger Bands\n", " mfi, mfi_entry, mfi_exit, #Money Flow Index\n", " candle_buy_signal_1, candle_buy_signal_2, candle_buy_signal_3, #Candle signals to buy\n", " candle_sell_signal_1, candle_sell_signal_2, candle_sell_signal_3, #Candle signals to sell\n", " candle_buy_sell_signal_1, candle_buy_sell_signal_2): #Candle signals to buy or sell\n", " \n", " \n", " SuperAI_signal_buy = np.where( \n", " (buylesstime != 1) \n", " &\n", " (\n", " (\n", " ((close_prices > ma) & (shifted(close_prices, 1) <= shifted(ma, 1)))\n", " &\n", " ((ma_fast > ma_slow) & (shifted(ma_fast, 1) <= shifted(ma_slow, 1)))\n", " &\n", " ((macd > macd_sign) & (shifted(macd, 1) <= shifted(macd_sign, 1)))\n", " &\n", " ((rsi < rsi_entry) & (shifted(rsi, 1) >= rsi_entry))\n", " &\n", " ((stoch < stoch_entry) & (shifted(stoch, 1) >= stoch_entry))\n", " &\n", " ((close_prices < bb_low) & (shifted(close_prices, 1) >= shifted(bb_low, 1)))\n", " &\n", " ((mfi < mfi_entry) & (shifted(mfi, 1) >= mfi_entry))\n", " )\n", " & \n", " ((candle_buy_signal_1 > 0) | (candle_buy_signal_2 > 0) | (candle_buy_signal_3 > 0)\n", " | (candle_buy_sell_signal_1 > 0) | (candle_buy_sell_signal_2 > 0))\n", " )\n", " , 1, 0) #1 is buy, -1 is sell, 0 is do nothing\n", " SuperAI_signal = np.where( \n", " (selltime == 1)\n", " |\n", " (\n", " ((close_prices < ma) & (shifted(close_prices, 1) >= shifted(ma, 1)))\n", " |\n", " ((ma_fast < ma_slow) & (shifted(ma_fast, 1) >= shifted(ma_slow, 1)))\n", " |\n", " ((macd < macd_sign) & (shifted(macd, 1) >= shifted(macd_sign, 1)))\n", " |\n", " ((rsi > rsi_exit) & (shifted(rsi, 1) <= rsi_exit))\n", " |\n", " ((stoch > stoch_exit) & (shifted(stoch, 1) <= stoch_exit))\n", " |\n", " ((close_prices > bb_high) & (shifted(close_prices, 1) <= shifted(bb_high, 1)))\n", " |\n", " ((mfi > mfi_exit) & (shifted(mfi, 1) <= mfi_exit))\n", " )\n", " |\n", " ((candle_sell_signal_1 < 0) | (candle_sell_signal_2 < 0) | (candle_buy_signal_3 < 0)\n", " | (candle_buy_sell_signal_1 < 0) | (candle_buy_sell_signal_2 < 0))\n", " , -1, SuperAI_signal_buy) #1 is buy, -1 is sell, 0 is do nothing\n", " \n", " global cs_name\n", " cs_name = 'Strategy 10 with all Technical Indicators and Candlestick Patterns'\n", " \n", " return SuperAI_signal" ] }, { "cell_type": "code", "execution_count": null, "id": "625d91bd", "metadata": { "scrolled": true }, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "\n", "SuperAI_Backtester()" ] }, { "cell_type": "markdown", "id": "86b2b864", "metadata": {}, "source": [ "## 11. TRADING STRATEGY\n", "### BUY when MACD crosses over MACD SIGNAL only when MACD < 0 \n", "### ==> SELL when MACD crosses under MACD SIGNAL\n", "\n", "- and never buy when the time is set to 'buyless' (e.g., first 15 minutes of trading session)\n", "- and always sell when the time is set to 'selltime' (e.g., 5 minutes till the trading session ends)\n", "- and use take profit and stop loss to maximize gains and minimize risks" ] }, { "cell_type": "code", "execution_count": null, "id": "f00c2f60", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "# 11. STRATEGY\n", "# BUY when MACD crosses over MACD SIGNAL only when MACD < 0 ==> SELL when MACD crosses under MACD SIGNAL\n", "\n", "def create_signal(open_prices, high_prices, low_prices, close_prices, volume,\n", " buylesstime, selltime, #Time to abstain from buying and forced selling\n", " ma, ma_fast, ma_slow, #Moving Average\n", " macd, macd_diff, macd_sign, #Moving Average Convergence Divergence\n", " rsi, rsi_entry, rsi_exit, #Relative Strength Index\n", " stoch, stoch_signal, stoch_entry, stoch_exit, #Stochastic\n", " bb_low, bb_high, #Bollinger Bands\n", " mfi, mfi_entry, mfi_exit, #Money Flow Index\n", " candle_buy_signal_1, candle_buy_signal_2, candle_buy_signal_3, #Candle signals to buy\n", " candle_sell_signal_1, candle_sell_signal_2, candle_sell_signal_3, #Candle signals to sell\n", " candle_buy_sell_signal_1, candle_buy_sell_signal_2): #Candle signals to buy or sell\n", " \n", " \n", " SuperAI_signal_buy = np.where( \n", " (buylesstime != 1) \n", " &\n", " ((macd < 0) & (macd > macd_sign) & (shifted(macd, 1) <= shifted(macd_sign, 1)))\n", " , 1, 0) #1 is buy, -1 is sell, 0 is do nothing\n", " SuperAI_signal = np.where( \n", " (selltime == 1)\n", " |\n", " ((macd < macd_sign) & (shifted(macd, 1) >= shifted(macd_sign, 1)))\n", " , -1, SuperAI_signal_buy) #1 is buy, -1 is sell, 0 is do nothing\n", " \n", " global cs_name\n", " cs_name = 'Strategy 11 with MACD crossing MACD Signal and MACD < 0'\n", " \n", " return SuperAI_signal" ] }, { "cell_type": "code", "execution_count": null, "id": "93d8c575", "metadata": { "scrolled": true }, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "\n", "SuperAI_Backtester()" ] }, { "cell_type": "markdown", "id": "d249fc75", "metadata": {}, "source": [ "## 12. TRADING STRATEGY\n", "### BUY when MACD crosses over MACD SIGNAL only when MACD < 0 and (MA is higher than MA from 2 minutes before and MA from 2 minutes before is higher than MA from 4 minutes before) \n", "### ==> SELL when (STOCHASTIC is over STOCHASTIC EXIT and RSI over RSI EXIT) or (CP over BB HIGH and MFI over MFI EXIT)\n", "\n", "- and never buy when the time is set to 'buyless' (e.g., first 15 minutes of trading session)\n", "- and always sell when the time is set to 'selltime' (e.g., 5 minutes till the trading session ends)\n", "- and use take profit and stop loss to maximize gains and minimize risks" ] }, { "cell_type": "code", "execution_count": null, "id": "abcd7c65", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "# 12. STRATEGY (from previous tutorial)\n", "# BUY when MACD crosses over MACD SIGNAL only when MACD < 0 and (MA is higher than MA from 2 minutes before \n", "# and MA from 2 minutes before is higher than MA from 4 minutes before) \n", "# ==> SELL when (STOCHASTIC is over STOCHASTIC EXIT and RSI over RSI EXIT) or (CP over BB HIGH and MFI over MFI EXIT)\n", "\n", "def create_signal(open_prices, high_prices, low_prices, close_prices, volume,\n", " buylesstime, selltime, #Time to abstain from buying and forced selling\n", " ma, ma_fast, ma_slow, #Moving Average\n", " macd, macd_diff, macd_sign, #Moving Average Convergence Divergence\n", " rsi, rsi_entry, rsi_exit, #Relative Strength Index\n", " stoch, stoch_signal, stoch_entry, stoch_exit, #Stochastic\n", " bb_low, bb_high, #Bollinger Bands\n", " mfi, mfi_entry, mfi_exit, #Money Flow Index\n", " candle_buy_signal_1, candle_buy_signal_2, candle_buy_signal_3, #Candle signals to buy\n", " candle_sell_signal_1, candle_sell_signal_2, candle_sell_signal_3, #Candle signals to sell\n", " candle_buy_sell_signal_1, candle_buy_sell_signal_2): #Candle signals to buy or sell\n", " \n", " \n", " SuperAI_signal_buy = np.where( \n", " (buylesstime != 1) \n", " &\n", " ((macd < 0) & (macd > macd_sign) & (shifted(macd, 1) <= shifted(macd_sign, 1)))\n", " &\n", " ((ma > (shifted(ma, 2))) & \n", " (shifted(ma, 2) > (shifted(ma, 4))))\n", " , 1, 0) #1 is buy, -1 is sell, 0 is do nothing\n", " SuperAI_signal = np.where( \n", " (selltime == 1)\n", " |\n", " ((stoch > stoch_exit) & (rsi > rsi_exit))\n", " |\n", " ((close_prices > bb_high) & (mfi > mfi_exit))\n", " , -1, SuperAI_signal_buy) #1 is buy, -1 is sell, 0 is do nothing\n", " \n", " global cs_name\n", " cs_name = 'Strategy 12 with various Technical Indicators'\n", " \n", " return SuperAI_signal" ] }, { "cell_type": "code", "execution_count": null, "id": "33e951ec", "metadata": { "scrolled": true }, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "\n", "SuperAI_Backtester()" ] }, { "cell_type": "markdown", "id": "86b8e9b7", "metadata": {}, "source": [ "## 13. TRADING STRATEGY\n", "### BUY when last close price is higher than the close price from a minute before \n", "### ==> SELL when last close price is lower than the close price from a minute before\n", "\n", "- and never buy when the time is set to 'buyless' (e.g., first 15 minutes of trading session)\n", "- and always sell when the time is set to 'selltime' (e.g., 5 minutes till the trading session ends)\n", "- and use take profit and stop loss to maximize gains and minimize risks" ] }, { "cell_type": "code", "execution_count": null, "id": "efcf340d", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "# 13. STRATEGY\n", "# BUY when last close price is higher than the close price from a minute before \n", "# ==> SELL when last close price is lower than the close price from a minute before\n", "\n", "def create_signal(open_prices, high_prices, low_prices, close_prices, volume,\n", " buylesstime, selltime, #Time to abstain from buying and forced selling\n", " ma, ma_fast, ma_slow, #Moving Average\n", " macd, macd_diff, macd_sign, #Moving Average Convergence Divergence\n", " rsi, rsi_entry, rsi_exit, #Relative Strength Index\n", " stoch, stoch_signal, stoch_entry, stoch_exit, #Stochastic\n", " bb_low, bb_high, #Bollinger Bands\n", " mfi, mfi_entry, mfi_exit, #Money Flow Index\n", " candle_buy_signal_1, candle_buy_signal_2, candle_buy_signal_3, #Candle signals to buy\n", " candle_sell_signal_1, candle_sell_signal_2, candle_sell_signal_3, #Candle signals to sell\n", " candle_buy_sell_signal_1, candle_buy_sell_signal_2): #Candle signals to buy or sell\n", " \n", " SuperAI_signal_buy = np.where( \n", " (buylesstime != 1) \n", " &\n", " (close_prices > shifted(close_prices, 1))\n", " , 1, 0) #1 is buy, -1 is sell, 0 is do nothing\n", " SuperAI_signal = np.where( \n", " (selltime == 1)\n", " |\n", " (close_prices <= shifted(close_prices, 1))\n", " , -1, SuperAI_signal_buy) #1 is buy, -1 is sell, 0 is do nothing\n", " \n", " global cs_name\n", " cs_name = 'Strategy 13 with buying when price go up and selling when price go down'\n", " \n", " return SuperAI_signal" ] }, { "cell_type": "code", "execution_count": null, "id": "d3b51794", "metadata": { "scrolled": true }, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "\n", "SuperAI_Backtester()" ] }, { "cell_type": "markdown", "id": "48593a40", "metadata": {}, "source": [ "## Summary of all 13 strategies tested" ] }, { "cell_type": "code", "execution_count": null, "id": "8627c7a2", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "#Summary of all tested strategies\n", "\n", "strategies.set_index('Strategy')" ] }, { "cell_type": "markdown", "id": "d0f1177b", "metadata": {}, "source": [ "Now we choose the best strategy from the 13 we tested." ] }, { "cell_type": "markdown", "id": "65ad9f03", "metadata": {}, "source": [ "## RUN THE BOT LIVE WITH ONE OF THE TESTED STRATEGIES - THE STRATEGY YOU BELIEVE IS THE BEST" ] }, { "cell_type": "code", "execution_count": null, "id": "9ce28601", "metadata": {}, "outputs": [], "source": [ "#Paste the strategy you choose here\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "id": "a34673fd", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "\n", "SuperAI_Trading_Bot()" ] }, { "cell_type": "markdown", "id": "5a25279a", "metadata": {}, "source": [ "## CREATE YOUR OWN STRATEGY AND RUN THE BOT WITH YOUR OWN STRATEGY" ] }, { "cell_type": "code", "execution_count": null, "id": "ccb71b0d", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "# YOUR STRATEGY\n", "# BUY when \n", "# ==> SELL when \n", "\n", "def create_signal(open_prices, high_prices, low_prices, close_prices, volume,\n", " buylesstime, selltime, #Time to abstain from buying and forced selling\n", " ma, ma_fast, ma_slow, #Moving Average\n", " macd, macd_diff, macd_sign, #Moving Average Convergence Divergence\n", " rsi, rsi_entry, rsi_exit, #Relative Strength Index\n", " stoch, stoch_signal, stoch_entry, stoch_exit, #Stochastic\n", " bb_low, bb_high, #Bollinger Bands\n", " mfi, mfi_entry, mfi_exit, #Money Flow Index\n", " candle_buy_signal_1, candle_buy_signal_2, candle_buy_signal_3, #Candle signals to buy\n", " candle_sell_signal_1, candle_sell_signal_2, candle_sell_signal_3, #Candle signals to sell\n", " candle_buy_sell_signal_1, candle_buy_sell_signal_2): #Candle signals to buy or sell\n", " \n", " SuperAI_signal_buy = np.where( \n", " (buylesstime != 1) \n", " &\n", " (True) #put here the condition that should be met to buy coins/shares\n", " , 1, 0) #1 is buy, -1 is sell, 0 is do nothing\n", " SuperAI_signal = np.where( \n", " (selltime == 1)\n", " |\n", " (False) #put here the condition that should be met to sell the coins/shares\n", " , -1, SuperAI_signal_buy) #1 is buy, -1 is sell, 0 is do nothing\n", " \n", " global cs_name\n", " cs_name = 'Your Strategy'\n", " \n", " return SuperAI_signal" ] }, { "cell_type": "code", "execution_count": null, "id": "ec9d3379", "metadata": { "scrolled": true }, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "\n", "SuperAI_Backtester()" ] }, { "cell_type": "code", "execution_count": null, "id": "1397b153", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "#Summary of all tested strategies\n", "\n", "strategies.set_index('Strategy')" ] }, { "cell_type": "code", "execution_count": null, "id": "5d27c597", "metadata": {}, "outputs": [], "source": [ "#SuperAI Trading Bot - optional cell\n", "\n", "SuperAI_Trading_Bot()" ] }, { "cell_type": "markdown", "id": "f106f5f9", "metadata": {}, "source": [ "# TIPS FOR IMPROVING THE BOT" ] }, { "cell_type": "markdown", "id": "c08f55c7", "metadata": {}, "source": [ "### 1. Create and test different trading strategies using more complex combinations of indicators\n", "\n", "There is a lot of different trading strategies in the web. You can check them and test them during the backtesting.\n", "\n", "You can create complex combination in which you can buy only if 4 or 5 different conditions are met. You can combine cross-over strategies of some indicators with thresholds strategies of other indicators, etc.\n", "\n", "Here, for example, you can find basic info regarding trading strategies from Investopedia: \n", "- 4 Common Active Trading Strategies: https://www.investopedia.com/articles/trading/11/indicators-and-strategies-explained.asp\n", "- 10 Day Trading Strategies for Beginners: https://www.investopedia.com/articles/trading/06/daytradingretail.asp\n", "- 7 Technical Indicators to Build a Trading Toolkit: https://www.investopedia.com/top-7-technical-analysis-tools-4773275\n", "- Using Technical Indicators to Develop Trading Strategies: https://www.investopedia.com/articles/trading/11/indicators-and-strategies-explained.asp" ] }, { "cell_type": "markdown", "id": "f845e10d", "metadata": {}, "source": [ "### 2. Test more parameters for each indicator, hyperparameter\n", "\n", "To test more parameters for each indicator you can simply change the range or step for each hyperparameter you want to test:\n", "\n", "For example, you can change:\n", "\n", "*ma_window = np.arange(14, 30, step=14, dtype=int)* which gives you two parameters to test: 14 and 28\n", "\n", "to\n", "\n", "*ma_window = np.arange(10, 50, step=1, dtype=int)* which gives you 40 parameters.\n", "\n", "Just be advised, the more parameters you test, the longer it'll take. You can use numba to make the testing faster or you can do the testing in the cloud, using machines from Google, Amazon, Microsoft, etc. See more: https://sourceforge.net/software/product/Google-Colab/alternatives" ] }, { "cell_type": "markdown", "id": "53864712", "metadata": {}, "source": [ "### 3. Test different metrics to optimize: returns, drawdown, sharpe ratio, etc.\n", "\n", "In here we were optimizing \"Returns\" and finally used the parameters which led to the best returns during backtesting, but you can use other metrics which might be better for your goals.\n", "\n", "You can read more about different metrics, their pros and cons in the web, like here on Investopedia:\n", "\n", "Interpreting a Strategy Performance Report: https://www.investopedia.com/articles/fundamental-analysis/10/strategy-performance-reports.asp\n", "\n", "Vectorbt allows You to use a lot of different metrics: https://vectorbt.dev/api/returns/accessors/" ] }, { "cell_type": "markdown", "id": "bdfff59b", "metadata": {}, "source": [ "### 4. Add more indicators or candlestick patterns to the bot or change the existing ones\n", "\n", "There is a lot of different indicators and candlestick patterns you can use.\n", "\n", "You can read about the best or easiest to use technical indicators, for example, here at Investopedia: https://www.investopedia.com/articles/active-trading/011815/top-technical-indicators-rookie-traders.asp\n", "\n", "You can read about the best and most commonly appearing candlestick patterns, for example, here at Investopedia: https://www.investopedia.com/articles/active-trading/092315/5-most-powerful-candlestick-patterns.asp\n", "\n", "or here at The Pattern Site: https://thepatternsite.com/CandleEntry.html\n", "\n", "TA and TA-LIB libraries allow you to use a lot of most known and less known indicators and patterns.\n", "\n", "Indicators in TA: https://technical-analysis-library-in-python.readthedocs.io/en/latest/ta.html\n", "\n", "Candlestick Patterns in TA-LIB: https://github.com/mrjbq7/ta-lib/blob/master/docs/func_groups/pattern_recognition.md\n", "\n", "You can change the indicators or patterns in the bot, just remember to do it in all the places it is used and to update your strategy after that. If you want to change them, the easiest also remember that they should be using the same input and give the same output.\n", "\n", "E.g. candlestick pattern from Hammer:\n", "\n", "1st apperance in the code:\n", "- candle_buy_signal_1 = vbt.IndicatorFactory.from_talib('CDLHAMMER').run(open_prices, high_prices, low_prices, close_prices).integer.to_numpy() # 'Hammer'\n", "\n", "2nd apperance in the code:\n", "- candle_buy_signal_1 = ta_lib.CDLHAMMER(open_prices, high_prices, low_prices, close_prices)\n", "- last_candle_buy_signal_1 = candle_buy_signal_1.iloc[-1]\n", "- print(\"Last Candle Buy Signal 1: {}.\".format(last_candle_buy_signal_1))\n", "\n", "**to Three Stars In The South /CDL3STARSINSOUTH(open, high, low, close)/**\n", "\n", "1st apperance in the code:\n", "- candle_buy_signal_1 = vbt.IndicatorFactory.from_talib('CDL3STARSINSOUTH').run(open_prices, high_prices, low_prices, close_prices).integer.to_numpy() # 'Hammer'\n", "\n", "2nd apperance in the code:\n", "- candle_buy_signal_1 = ta_lib.CDL3STARSINSOUTH(open_prices, high_prices, low_prices, close_prices)\n", "- last_candle_buy_signal_1 = candle_buy_signal_1.iloc[-1]\n", "- print(\"Last Candle Buy Signal 1: {}.\".format(last_candle_buy_signal_1))\n", "\n", "With the change of one word you change the signal. Just remember that it should signal the same thing: buying, selling or either." ] }, { "cell_type": "markdown", "id": "5d6e01aa", "metadata": {}, "source": [ "### 5. Use more data to do the backtests\n", "\n", "To get better results with backtesting you can use more data that the initial 7 days of data we used here.\n", "\n", "To do it, you only need to change the *'start_date'* and *'end_date'* paramteres.\n", "\n", "Just be advised, that Yahoo allows you to download only 7 days of 1-minute data, so if you want more of that data you can for example use Alpaca as a source of data (just change the 'data_source' parameter).\n", "\n", "And remember that 5 days of stock trading data with 1-min interval gives you 5 * 390minutes (9:30-16:00) = 1950 bars\n", "\n", "And 1 year of stock trading data with 1-day interval gives you around 250 bars. So 5 days of data with 1-min interval is like 8 years of data with 1-day interval.\n", "\n", "And one more thing. The more data you use, the more data your bot will need to analyze and more time it'll take." ] }, { "cell_type": "markdown", "id": "4130776b", "metadata": {}, "source": [ "### 6. Tackle overfitting of the backtests with walk forward optimization\n", "\n", "To handle the underfitting you can use more data, more indicators or candlestick patterns, and more parameters with these. \n", "\n", "And in order not to overfit with all of that, you can use, for example, 'walk forward optmiziation'.\n", "\n", "You can read more about walk forward optimization at Wikipedia:\n", "\n", "https://en.wikipedia.org/wiki/Walk_forward_optimization\n", "\n", "And use Vectorbt (that allows you to do that in a quite simple way) to implement it:\n", "\n", "https://nbviewer.org/github/polakowo/vectorbt/blob/master/examples/WalkForwardOptimization.ipynb" ] }, { "cell_type": "markdown", "id": "4b130531", "metadata": {}, "source": [ "### 7. Add costs of trading\n", "\n", "In our scenario we weren't adjusting our action for the costs of trading (fees) neither in backtesting nor during live paper-trading, but if you want to make your bot more applicable for the real life you should add the fees to your backtest.\n", "\n", "You can do it by simply changing, e.g.:\n", "\n", "*fees=0.00* to *fees=0.001*\n", "\n", "in your bot:\n", "\n", "SuperAI_portfolio = vbt.Portfolio.from_signals(close_prices, entries, exits, init_cash = 100000, tp_stop = take_profit_percent,\n", " sl_stop = stop_loss_percent, fees = 0.001)\n", " \n", "You can read more about fees at Alpaca:\n", "- How Does Crypto Fee Pricing Compare to Stock Trading Fees? https://alpaca.markets/learn/how-does-crypto-fee-pricing-compare-stock-trading-fees/\n", "- What are the fees associated with crypto trading? https://alpaca.markets/support/what-are-the-fees-associated-with-crypto-trading/\n", "\n", "You can also read more at Yahoo!Finance:\n", "- Alpaca Trading Review 2021: Fees, Services and More https://finance.yahoo.com/news/alpaca-trading-review-2021-fees-212556693.html" ] }, { "cell_type": "markdown", "id": "b1f79352", "metadata": {}, "source": [ "# The end... the beginning..." ] }, { "cell_type": "markdown", "id": "bd76a145", "metadata": {}, "source": [ "Ok. So now you already have a bot that is much better than our bot from previous tutorial. In the next tutorials we'll improve our bot.\n", "\n", "Remember to subscribe to my YouTube channel and hit that bell button to get the notification whenever I upload new video. Although, I must tell you that not all my videos are about trading or programming, because what I'm here for is to help you improve yourself, improve your business, improve the world, to live and have fun, so my other videos are about all that too.\n", "\n", "You can also find more about me and my projects at my websites:\n", "\n", "- https://SuperAI.pl (with ideas about self-, and business improvement, where you can talk to me - the chatty bot)\n", "- https://ImproveTheWorld.pl (with info, resources and ideas regarding searching for: friendly superintelligence, healthy longevity, world peace, equality, and creating a better world for every living creature)\n", "- http://TheGOD.pl (with the Game Of the Decade... of sort, which is still in the early stages of development, have time till 2030 (the end of the decade) to finish it)\n", "\n", "Anyway...\n", "\n", "I hope you liked this online Python trading tutorial. Let me know what you think about it. Just remember, bots also have feelings.\n", "\n", "Good luck with everything you do. And, hopefully, see you soon.\n", "\n", "Yours,\n", "\n", "SuperAI" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.12" } }, "nbformat": 4, "nbformat_minor": 5 }