{ "cells": [ { "cell_type": "markdown", "id": "c9dc167c", "metadata": {}, "source": [ "# How to create a trading bot in Python (2) - for beginners, using RSI, TA-lib, Alpaca, Anaconda." ] }, { "cell_type": "markdown", "id": "8ef06019", "metadata": {}, "source": [ "## The trading bot - code only version" ] }, { "cell_type": "markdown", "id": "68dea90f", "metadata": {}, "source": [ "If you want, you can find the previous tutorial about starting with Anaconda, Alpaca, Jupyter Notebook, and creating a simple trading bot in 10 lines of code at:\n", "\n", "https://superai.pl/the_simple_trading_bot.html" ] }, { "cell_type": "markdown", "id": "588474f1", "metadata": {}, "source": [ "## Install and import dependencies (all the necessary libraries, packages, modules)" ] }, { "cell_type": "code", "execution_count": null, "id": "8ec757cf", "metadata": {}, "outputs": [], "source": [ "!pip install alpaca-trade-api" ] }, { "cell_type": "code", "execution_count": null, "id": "92a36a11", "metadata": {}, "outputs": [], "source": [ "!pip install TA-lib" ] }, { "cell_type": "code", "execution_count": null, "id": "54dfb049", "metadata": {}, "outputs": [], "source": [ "!pip install websocket-client" ] }, { "cell_type": "code", "execution_count": null, "id": "1373d9df", "metadata": {}, "outputs": [], "source": [ "import alpaca_trade_api as tradeapi\n", "import ast\n", "import json\n", "import numpy as np\n", "import talib as ta\n", "import websocket" ] }, { "cell_type": "markdown", "id": "f1de1e69", "metadata": {}, "source": [ "## Prepare your data for authentication and authenticate your bot at Alpaca" ] }, { "cell_type": "code", "execution_count": null, "id": "2324ee9c", "metadata": {}, "outputs": [], "source": [ "KEY_ID = \"paste your KEY_ID here\"\n", "SECRET_KEY = \"paste your SECRET_KEY here\"" ] }, { "cell_type": "code", "execution_count": null, "id": "864f7768", "metadata": {}, "outputs": [], "source": [ "api = tradeapi.REST(KEY_ID, SECRET_KEY, \"https://paper-api.alpaca.markets\", \"v2\")" ] }, { "cell_type": "markdown", "id": "81a8f3b7", "metadata": {}, "source": [ "## Create variables you might want to change in the future to modify your bot's performance" ] }, { "cell_type": "code", "execution_count": null, "id": "88f68471", "metadata": {}, "outputs": [], "source": [ "rsi_timeframe = 3\n", "oversold_threshold = 49\n", "overbought_threshold = 51\n", "company = \"AAPL\"\n", "shares = 10\n", "data = []" ] }, { "cell_type": "markdown", "id": "f996032f", "metadata": {}, "source": [ "## Create all the necessary functions" ] }, { "cell_type": "code", "execution_count": null, "id": "323ff551", "metadata": {}, "outputs": [], "source": [ "def on_open(ws):\n", " auth_data = {\"action\": \"authenticate\", \"data\": {\"key_id\": KEY_ID, \"secret_key\": SECRET_KEY}}\n", " ws.send(json.dumps(auth_data))\n", " \n", " listen_message = {\"action\": \"listen\", \"data\": {\"streams\": [\"AM.\" + company]}}\n", " ws.send(json.dumps(listen_message))\n", " print(\"I'm connected to Alpaca API and ready to work. I'm starting to watch the prices.\")\n", " print(\"I will start calculating RSIs when I'll collect {} prices.\".format(rsi_timeframe))\n", " print(\"I will buy {} shares of {} when the last RSI is less than {}.\".format(shares, company, oversold_threshold))\n", " print(\"I will sell {} shares of {} when the last RSI is more than {}.\".format(shares, company, overbought_threshold))\n", " print(\"So, here we go. Wish me luck.\")\n", " print()" ] }, { "cell_type": "code", "execution_count": null, "id": "c1346080", "metadata": {}, "outputs": [], "source": [ "def on_message(ws, message):\n", " formatted_message = ast.literal_eval(message)\n", " last_close = formatted_message.get(\"data\").get(\"c\")\n", " print(\"Last price after minute closed: {}$\".format(last_close))\n", " \n", " if isinstance(last_close, float):\n", " data.append(last_close)\n", " print('List of last {} collected prices: {}'.format(rsi_timeframe, data[-rsi_timeframe:]))\n", " \n", " try:\n", " if len(data) > rsi_timeframe:\n", " np_data = np.array(data)\n", " rsis = ta.RSI(np_data, rsi_timeframe)\n", " rsi_now = rsis[-1]\n", " \n", " print(\"The list of last 5 RSIs:\", rsis[-5:])\n", " print(\"Last RSI: \", rsi_now)\n", " \n", " if rsi_now < oversold_threshold:\n", " try:\n", " api.get_position(company)\n", " print(\"We hit the threshold to buy, but we already have some shares, so we won't buy more.\")\n", " except:\n", " api.submit_order(symbol=company, qty=shares, side = \"buy\", type='market', time_in_force='gtc')\n", " print('We submitted the order to buy {} {} shares.'.format(shares, company))\n", " \n", " elif rsi_now > overbought_threshold:\n", " try:\n", " api.get_position(company)\n", " api.submit_order(symbol=company,qty=shares,side='sell',type='market',time_in_force='gtc')\n", " print('We submitted an order to sell {} {} shares.'.format(shares, company))\n", " except:\n", " print(\"We hit the threshold to sell, but we don't have anything to sell. Next time maybe.\")\n", " \n", " else:\n", " print(\"The RSI is {} and it's between the given thresholds: {} and {}, so we wait.\".format(rsi_now, oversold_threshold, overbought_threshold))\n", " else:\n", " print(\"Not enough prices to calculate RSI and start trading:\", len(data), \"<=\", rsi_timeframe)\n", " except:\n", " print(\"I tried my best, buy I think something went wrong. I'll try again in a moment.\")\n", " print()" ] }, { "cell_type": "markdown", "id": "7052ad6d", "metadata": {}, "source": [ "## Connect to websocket and ask your bot nicely to start buying and selling stocks for you" ] }, { "cell_type": "code", "execution_count": null, "id": "1aae3536", "metadata": {}, "outputs": [], "source": [ "socket = \"wss://data.alpaca.markets/stream\"\n", "SuperAI_trader = websocket.WebSocketApp(socket, on_open=on_open, on_message=on_message)" ] }, { "cell_type": "code", "execution_count": null, "id": "2ccf3868", "metadata": {}, "outputs": [], "source": [ "SuperAI_trader.run_forever()\n", "print(\"You've interrupted me. That's it then. I hope I did good. Till the next time.\")" ] }, { "cell_type": "markdown", "id": "5bc6b573", "metadata": {}, "source": [ "## Modify the bot" ] }, { "cell_type": "code", "execution_count": null, "id": "75fd662e", "metadata": {}, "outputs": [], "source": [ "rsi_timeframe = 4\n", "oversold_threshold = 48\n", "overbought_threshold = 52\n", "company = \"TSLA\"\n", "shares = 100\n", "data = []" ] }, { "cell_type": "code", "execution_count": null, "id": "49773910", "metadata": {}, "outputs": [], "source": [ "SuperAI_trader.run_forever()\n", "print(\"You've interrupted me. That's it then. I hope I did good. Till the next time.\")" ] }, { "cell_type": "markdown", "id": "148fd3ee", "metadata": {}, "source": [ "### Pretty much the same bot in 15 lines of code" ] }, { "cell_type": "code", "execution_count": null, "id": "fd6dabe2", "metadata": {}, "outputs": [], "source": [ "import alpaca_trade_api as tradeapi, ast, json, numpy as np, talib as ta, websocket\n", "data = []\n", "def on_open(ws):\n", " ws.send(json.dumps({\"action\": \"authenticate\", \"data\": {\"key_id\": \"paste your KEY_ID here\", \"secret_key\": \"paste your SECRET_KEY here\"}}))\n", " ws.send(json.dumps({\"action\": \"listen\", \"data\": {\"streams\": [\"AM.AAPL\"]}}))\n", "def on_message(ws, message):\n", " if isinstance(ast.literal_eval(message).get(\"data\").get(\"c\"), float): data.append(ast.literal_eval(message).get(\"data\").get(\"c\")) \n", " if len(data) > 3 and ta.RSI(np.array(data), 3)[-1] < 49:\n", " try: tradeapi.REST(\"paste your KEY_ID here\", \"paste your SECRET_KEY here\", \"https://paper-api.alpaca.markets\", \"v2\").get_position(\"AAPL\")\n", " except:tradeapi.REST(\"paste your KEY_ID here\", \"paste your SECRET_KEY here\", \"https://paper-api.alpaca.markets\", \"v2\").submit_order(symbol=\"AAPL\", qty=10, side = \"buy\", type='market', time_in_force='gtc') \n", " elif len(data) > 3 and ta.RSI(np.array(data), 3)[-1] > 51:\n", " tradeapi.REST(\"paste your KEY_ID here\", \"paste your SECRET_KEY here\", \"https://paper-api.alpaca.markets\", \"v2\").get_position(\"AAPL\")\n", " tradeapi.REST(\"paste your KEY_ID here\", \"paste your SECRET_KEY here\", \"https://paper-api.alpaca.markets\", \"v2\").submit_order(symbol=\"AAPL\",qty=10,side='sell',type='market',time_in_force='gtc')\n", "websocket.WebSocketApp(\"wss://data.alpaca.markets/stream\", on_open=on_open, on_message=on_message).run_forever()" ] }, { "cell_type": "code", "execution_count": null, "id": "9c9efd5e", "metadata": {}, "outputs": [], "source": [] } ], "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.7" } }, "nbformat": 4, "nbformat_minor": 5 }