├── .github └── workflows │ └── lint_python.yml ├── .gitignore ├── README.md ├── ai-trading-system ├── .coveragerc ├── Dockerfile ├── pytest.ini ├── requirements.txt ├── setup.py └── src │ ├── app.py │ ├── application │ ├── __init__.py │ ├── actions │ │ ├── __init__.py │ │ └── trading_system.py │ ├── clients │ │ ├── __init__.py │ │ ├── ai_client.py │ │ ├── alpaca_client.py │ │ ├── logger_client.py │ │ ├── robinhood_client.py │ │ └── yahoo_client.py │ └── repositories │ │ ├── __init__.py │ │ ├── ai_repository.py │ │ ├── alpaca_repository.py │ │ └── yahoo_repository.py │ ├── config │ ├── __init__.py │ └── config.py │ └── tests │ └── __init__.py ├── docker-compose.yml └── original_boilerplate ├── handler.py ├── requirements.txt └── serverless.yml /.github/workflows/lint_python.yml: -------------------------------------------------------------------------------- 1 | name: lint_python 2 | on: [pull_request, push] 3 | jobs: 4 | lint_python: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v2 8 | - uses: actions/setup-python@v2 9 | - run: pip install flake8 10 | - run: flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Distribution / packaging 2 | .Python 3 | venv/ 4 | env/ 5 | .env 6 | build/ 7 | develop-eggs/ 8 | dist/ 9 | downloads/ 10 | eggs/ 11 | .eggs/ 12 | lib/ 13 | lib64/ 14 | parts/ 15 | sdist/ 16 | var/ 17 | *.egg-info/ 18 | .installed.cfg 19 | *.egg 20 | __pycache__ 21 | 22 | # Serverless directories 23 | .serverless -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AI Based Trading System 2 | 3 | This code works as a boilerplate for an AI based trading system with yfinance as data source and RobinHood or Alpaca as brokers. DO NOT USE IT FOR TRADING AS IT IS. Follow [the tutorial in Medium.](https://towardsdatascience.com/how-to-create-a-fully-automated-ai-based-trading-system-with-python-708503c1a907) 4 | 5 | Since I plan to keep writing on this topic I'm moving the original boilerplate to the `original_boilerplate` folder - without removing anything. I'll keep the `ai-trading-system` folder polished and more production-ready. 6 | 7 | Usage so far: 8 | 9 | ``` 10 | $ sudo dockerd 11 | $ docker-compose up --build ai-trading-system 12 | ``` 13 | 14 | Stay tuned! 15 | -------------------------------------------------------------------------------- /ai-trading-system/.coveragerc: -------------------------------------------------------------------------------- 1 | # https://coverage.readthedocs.io/en/latest/config.html 2 | # .coveragerc to control coverage.py embbed in pytest --cov 3 | [run] 4 | branch = True 5 | omit = 6 | .* 7 | */env/* 8 | */*-env/* 9 | */venv/* 10 | */config/* 11 | *setup.py* 12 | *__init__.py** 13 | *_test.py 14 | *app.py 15 | */dist-packages/* 16 | */site-packages/* 17 | [paths] 18 | source = 19 | . 20 | [report] 21 | # Regexes for lines to exclude from consideration 22 | exclude_lines = 23 | # Have to re-enable the standard pragma 24 | pragma: no cover 25 | 26 | # Don't complain about missing debug-only code: 27 | def __repr__ 28 | if self\.debug 29 | 30 | # Don't complain if non-runnable code isn't run: 31 | if 0: 32 | if __name__ == .__main__.: 33 | 34 | ignore_errors = False 35 | fail_under = 90 36 | precision = 2 37 | show_missing = True 38 | 39 | [html] 40 | directory = coverage_html_report -------------------------------------------------------------------------------- /ai-trading-system/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.8.3-slim 2 | 3 | COPY ai-trading-system/ /service/app 4 | 5 | WORKDIR /service/app 6 | 7 | RUN apt-get update && apt-get install gcc npm -y && apt-get clean 8 | RUN pip install --upgrade pip 9 | RUN pip install -r requirements.txt 10 | 11 | EXPOSE 8081 12 | 13 | ENV PYTHONUNBUFFERED 1 14 | 15 | HEALTHCHECK --timeout=30s --interval=1m30s --retries=5 \ 16 | CMD curl -s --fail http://localhost:8081/_health || exit 1 17 | 18 | CMD ["python3", "-u", "src/app.py"] -------------------------------------------------------------------------------- /ai-trading-system/pytest.ini: -------------------------------------------------------------------------------- 1 | # From https://docs.pytest.org/en/latest/example/pythoncollection.html#changing-naming-conventions 2 | [pytest] 3 | addopts = -vv 4 | testpaths = src/tests 5 | norecursedirs = .* env 6 | python_files = *_test.py 7 | python_classes = Test 8 | python_functions = *_test -------------------------------------------------------------------------------- /ai-trading-system/requirements.txt: -------------------------------------------------------------------------------- 1 | yfinance==0.1.55 2 | pandas==1.1.5 3 | numpy==1.19.4 4 | statsmodels==0.12.1 5 | pyotp==2.4.1 6 | robin-stocks==1.5.3 7 | matplotlib==3.3.3 8 | alpaca-trade-api==0.51.0 -------------------------------------------------------------------------------- /ai-trading-system/setup.py: -------------------------------------------------------------------------------- 1 | # This will be executed everytime we make a pip install 2 | # The find_packages is very important since it's used to 3 | # make all our packages visible to each other inside the project 4 | 5 | from setuptools import setup, find_packages 6 | setup( 7 | name='Winteam Bridge', 8 | version='1.0.0', 9 | description='Brosnan\'s winteam bridge', 10 | packages=find_packages(exclude=['*tests']), 11 | include_package_data=True, 12 | setup_requires=[ 13 | 'pytest-runner', 14 | ], 15 | test_suite='test.unittest' 16 | ) 17 | -------------------------------------------------------------------------------- /ai-trading-system/src/app.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | from application.clients.logger_client import LoggerClient 4 | from application.clients.yahoo_client import YahooClient 5 | from application.clients.alpaca_client import AlpacaClient 6 | from application.clients.robinhood_client import RobinHoodClient 7 | from application.clients.ai_client import AIClient 8 | from application.repositories.yahoo_repository import YahooRepository 9 | from application.repositories.alpaca_repository import AlpacaRepository 10 | from application.repositories.ai_repository import AIRepository 11 | from application.actions.trading_system import TradingSystem 12 | 13 | from config import config 14 | 15 | 16 | class Container: 17 | 18 | def __init__(self): 19 | self._logger = LoggerClient(config).get_logger() 20 | self._logger.info("AI trading system starting...") 21 | 22 | self._yahoo_client = YahooClient(self._logger, config) 23 | self._yahoo_repository = YahooRepository(self._logger, config, self._yahoo_client) 24 | self._ai_client = AIClient(self._logger, config) 25 | self._ai_repository = AIRepository(self._logger, config, self._ai_client) 26 | self._alpaca_client = AlpacaClient(self._logger, config) 27 | self._alpaca_repository = AlpacaRepository(self._logger, config, self._alpaca_client) 28 | self._trading_system = TradingSystem( 29 | self._logger, config, self._yahoo_repository, self._ai_repository, self._alpaca_repository) 30 | 31 | async def start_monitoring(self): 32 | await self._trading_system.monitoring(config.POLLING_CONFIG['yahoo_interval'], exec_on_start=True) 33 | 34 | 35 | if __name__ == '__main__': 36 | container = Container() 37 | loop = asyncio.get_event_loop() 38 | asyncio.ensure_future(container.start_monitoring(), loop=loop) 39 | loop.run_forever() 40 | -------------------------------------------------------------------------------- /ai-trading-system/src/application/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruromgar/python-ai-trading-system/018c3fc9f72657ab6b2def6d1c52b01ee9542639/ai-trading-system/src/application/__init__.py -------------------------------------------------------------------------------- /ai-trading-system/src/application/actions/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruromgar/python-ai-trading-system/018c3fc9f72657ab6b2def6d1c52b01ee9542639/ai-trading-system/src/application/actions/__init__.py -------------------------------------------------------------------------------- /ai-trading-system/src/application/actions/trading_system.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | import pandas as pd 4 | import numpy as np 5 | 6 | from statsmodels.tsa.arima.model import ARIMA 7 | 8 | 9 | class TradingSystem: 10 | def __init__(self, logger, config, yahoo_repository, ai_repository, alpaca_repository): 11 | self._config = config 12 | self._logger = logger 13 | 14 | self._yahoo_repository = yahoo_repository 15 | self._ai_repository = ai_repository 16 | self._alpaca_repository = alpaca_repository 17 | 18 | async def monitoring(self, seconds, exec_on_start): 19 | if not exec_on_start: 20 | await asyncio.sleep(seconds) 21 | 22 | while True: 23 | self._alpaca_repository.is_market_open() 24 | await asyncio.sleep(seconds) 25 | -------------------------------------------------------------------------------- /ai-trading-system/src/application/clients/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruromgar/python-ai-trading-system/018c3fc9f72657ab6b2def6d1c52b01ee9542639/ai-trading-system/src/application/clients/__init__.py -------------------------------------------------------------------------------- /ai-trading-system/src/application/clients/ai_client.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import numpy as np 3 | 4 | from statsmodels.tsa.arima.model import ARIMA 5 | 6 | 7 | class AIClient: 8 | def __init__(self, logger, config): 9 | self._config = config 10 | self._logger = logger 11 | 12 | def get_forecast(self, finance_data): 13 | self._logger.info('Calculating forecast with the given data...') 14 | # Assuming that we've properly trained the model before and that the 15 | # hyperparameters are correctly tweaked, we use the full dataset to fit 16 | y = finance_data['Low'].values 17 | model = ARIMA(y, order=(5,0,1)).fit() 18 | forecast = model.forecast(steps=1)[0] 19 | 20 | # Returning the last real data and the forecast for the next minute 21 | return (y[len(y)-1], forecast) -------------------------------------------------------------------------------- /ai-trading-system/src/application/clients/alpaca_client.py: -------------------------------------------------------------------------------- 1 | import alpaca_trade_api as alpaca 2 | 3 | 4 | class AlpacaClient: 5 | def __init__(self, logger, config): 6 | self._config = config 7 | self._logger = logger 8 | 9 | self._key_id = self._config.ALPACA_CONFIG['key_id'] 10 | self._secret_key = self._config.ALPACA_CONFIG['secret_key'] 11 | self._base_url = self._config.ALPACA_CONFIG['base_url'] 12 | 13 | self._api = alpaca.REST(self._key_id, self._secret_key, base_url=self._base_url) 14 | 15 | def get_account_info(self): 16 | account = self._api.get_account() 17 | print( 18 | f'The buying power is {acc.buying_power} {acc.currency} ' 19 | f'and the equity is {acc.equity} {acc.currency}\n' 20 | f'The account status is {account.status}' 21 | ) 22 | 23 | def is_market_open(self): 24 | clock = self._api.get_clock() 25 | return clock.is_open 26 | 27 | def get_prices(self, asset_symbol): 28 | # Get daily price data for GOOG over the last 5 trading days. 29 | barset = self._api.get_barset('GOOG', 'day', limit=5) 30 | bars = barset['GOOG'] 31 | 32 | # See how much GOOG moved in that timeframe. 33 | week_open = bars[0].o 34 | week_close = bars[-1].c 35 | percent_change = (week_close - week_open) / week_open * 100 36 | print(f'GOOG moved {percent_change}% over the last 5 days') 37 | 38 | def get_portfolio(self): 39 | # Get a list of all of our positions. 40 | portfolio = self._api.list_positions() 41 | 42 | # Get our position in GOOG. 43 | position = self._api.get_position('GOOG') 44 | 45 | def trade_alpaca(self, last_real_data, forecast): 46 | api = alpaca.REST(self._key_id, self._secret_key, base_url=self._base_url) 47 | 48 | last_real_data, forecast = get_forecast() 49 | 50 | # Your code to decide if you want to buy or sell 51 | # (and the number of shares) goes here 52 | action = 'BUY' # or 'SELL', or 'HOLD', or... 53 | shares = 1 54 | 55 | if action == 'BUY': 56 | api.submit_order(symbol='GOOG', qty=shares, side='buy', type='market', time_in_force='day') 57 | return f'Bought {shares} shares.' 58 | elif action == 'SELL': 59 | api.submit_order(symbol='GOOG', qty=shares, side='sell', type='market', time_in_force='day') 60 | return f'Sold {shares} shares.' 61 | else: 62 | return f'No shares were bought nor sold.' 63 | -------------------------------------------------------------------------------- /ai-trading-system/src/application/clients/logger_client.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | 4 | class LoggerClient: 5 | 6 | _config = None 7 | 8 | def __init__(self, config): 9 | self._config = config.LOG_CONFIG 10 | 11 | def get_logger(self): 12 | logger = logging.getLogger(self._config['name']) 13 | logger.setLevel(self._config['level']) 14 | log_handler = self._config['stream_handler'] 15 | formatter = logging.Formatter(self._config['format']) 16 | log_handler.setFormatter(formatter) 17 | logger.addHandler(log_handler) 18 | return logger 19 | -------------------------------------------------------------------------------- /ai-trading-system/src/application/clients/robinhood_client.py: -------------------------------------------------------------------------------- 1 | import robin_stocks as robinhood 2 | import pyotp 3 | 4 | 5 | class RobinHoodClient: 6 | def __init__(self, logger, config): 7 | self._config = config 8 | self._logger = logger 9 | 10 | self._rh_mfa_code = self._config.ROBINHOOD_CONFIG['mfa'] 11 | self._rh_user_email = self._config.ROBINHOOD_CONFIG['mail'] 12 | self._rh_password = self._config.ROBINHOOD_CONFIG['password'] 13 | 14 | def trade_robinhood(self, last_real_data, forecast): 15 | timed_otp = pyotp.TOTP(self._rh_mfa_code).now() 16 | login = rh.login(self._rh_user_email, self._rh_password, mfa_code=timed_otp) 17 | 18 | last_real_data, forecast = get_forecast() 19 | 20 | # Your code to decide if you want to buy or sell 21 | # (and the number of shares) goes here 22 | action = 'BUY' # or 'SELL', or 'HOLD', or... 23 | shares = 1 24 | 25 | if action == 'BUY': 26 | rh.order_buy_market('GOOG', shares) 27 | return f'Bought {shares} shares.' 28 | elif action == 'SELL': 29 | rh.order_sell_market('GOOG', shares) 30 | return f'Sold {shares} shares.' 31 | else: 32 | return f'No shares were bought nor sold.' 33 | -------------------------------------------------------------------------------- /ai-trading-system/src/application/clients/yahoo_client.py: -------------------------------------------------------------------------------- 1 | import yfinance as yf 2 | import pandas as pd 3 | 4 | 5 | class YahooClient: 6 | def __init__(self, logger, config): 7 | self._config = config 8 | self._logger = logger 9 | 10 | def get_finance_data(self): 11 | self._logger.info('Getting data from Yahoo Finance...') 12 | 13 | google = yf.Ticker("GOOG") 14 | df = google.history(period='5d', interval="1m")[['Low']] 15 | self._logger.info(f'Data found. Last value dated on {df.index[-1]}') 16 | df['date'] = pd.to_datetime(df.index).time 17 | df.set_index('date', inplace=True) 18 | 19 | return df 20 | -------------------------------------------------------------------------------- /ai-trading-system/src/application/repositories/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruromgar/python-ai-trading-system/018c3fc9f72657ab6b2def6d1c52b01ee9542639/ai-trading-system/src/application/repositories/__init__.py -------------------------------------------------------------------------------- /ai-trading-system/src/application/repositories/ai_repository.py: -------------------------------------------------------------------------------- 1 | class AIRepository: 2 | def __init__(self, logger, config, ai_client): 3 | self._config = config 4 | self._logger = logger 5 | 6 | self._ai_client = ai_client 7 | 8 | def get_forecast(self, finance_data): 9 | return self._ai_client.get_forecast(finance_data) -------------------------------------------------------------------------------- /ai-trading-system/src/application/repositories/alpaca_repository.py: -------------------------------------------------------------------------------- 1 | class AlpacaRepository: 2 | def __init__(self, logger, config, alpaca_client): 3 | self._config = config 4 | self._logger = logger 5 | 6 | self._alpaca_client = alpaca_client 7 | 8 | def is_market_open(self): 9 | return self._alpaca_client.is_market_open() -------------------------------------------------------------------------------- /ai-trading-system/src/application/repositories/yahoo_repository.py: -------------------------------------------------------------------------------- 1 | class YahooRepository: 2 | def __init__(self, logger, config, yahoo_client): 3 | self._config = config 4 | self._logger = logger 5 | 6 | self._yahoo_client = yahoo_client 7 | 8 | def get_finance_data(self): 9 | return self._yahoo_client.get_finance_data() -------------------------------------------------------------------------------- /ai-trading-system/src/config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruromgar/python-ai-trading-system/018c3fc9f72657ab6b2def6d1c52b01ee9542639/ai-trading-system/src/config/__init__.py -------------------------------------------------------------------------------- /ai-trading-system/src/config/config.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import os 3 | import sys 4 | 5 | 6 | LOG_CONFIG = { 7 | 'name': 'ai-trading-bridge', 8 | 'level': logging.DEBUG, 9 | 'stream_handler': logging.StreamHandler(sys.stdout), 10 | 'format': '%(asctime)s: %(module)s: %(levelname)s: %(message)s' 11 | } 12 | 13 | POLLING_CONFIG = { 14 | 'yahoo_interval': 3000, 15 | } 16 | 17 | ROBINHOOD_CONFIG = { 18 | 'mail': os.environ['RH_USER_EMAIL'], 19 | 'password': os.environ['RH_PASSWORD'], 20 | 'mfa': os.environ['RH_MFA_CODE'] 21 | } 22 | 23 | ALPACA_CONFIG = { 24 | 'key_id': os.environ['ALPACA_KEY_ID'], 25 | 'secret_key': os.environ['ALPACA_SECRET_KEY'], 26 | # Change to https://api.alpaca.markets for live 27 | 'base_url': 'https://paper-api.alpaca.markets' 28 | } 29 | -------------------------------------------------------------------------------- /ai-trading-system/src/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruromgar/python-ai-trading-system/018c3fc9f72657ab6b2def6d1c52b01ee9542639/ai-trading-system/src/tests/__init__.py -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.3' 2 | services: 3 | 4 | ai-trading-system: 5 | restart: on-failure 6 | build: 7 | context: . 8 | dockerfile: ai-trading-system/Dockerfile 9 | env_file: 10 | - ai-trading-system/src/config/.env 11 | ports: 12 | - 8081:8081 13 | command: > 14 | /bin/sh -c " 15 | npm install -g nodemon && nodemon -e py --watch src --exec 'python3 -u src/app.py'; 16 | " 17 | volumes: 18 | - ./ai-trading-system/src:/service/app/src 19 | hostname: ai-trading-system 20 | 21 | volumes: 22 | db_data: -------------------------------------------------------------------------------- /original_boilerplate/handler.py: -------------------------------------------------------------------------------- 1 | import yfinance as yf 2 | import pandas as pd 3 | import numpy as np 4 | 5 | from statsmodels.tsa.arima.model import ARIMA 6 | 7 | import pyotp 8 | import robin_stocks as robinhood 9 | import alpaca_trade_api as alpaca 10 | 11 | import telegram 12 | import sys 13 | import os 14 | 15 | import matplotlib.pyplot as plt 16 | plt.style.use('fivethirtyeight') 17 | 18 | 19 | RH_USER_EMAIL = os.environ['RH_USER_EMAIL'] 20 | RH_PASSWORD = os.environ['RH_PASSWORD'] 21 | RH_MFA_CODE = os.environ['RH_MFA_CODE'] 22 | 23 | ALPACA_KEY_ID = os.environ['ALPACA_KEY_ID'] 24 | ALPACA_SECRET_KEY = os.environ['ALPACA_SECRET_KEY'] 25 | # Change to https://api.alpaca.markets for live 26 | BASE_URL = 'https://paper-api.alpaca.markets' 27 | 28 | CHAT_ID = 'XXXXXXXX' 29 | TOKEN = os.environ['TELEGRAM_TOKEN'] 30 | 31 | 32 | def get_finance_data(): 33 | google = yf.Ticker("GOOG") 34 | 35 | df = google.history(period='1d', interval="1m")[['Low']] 36 | df['date'] = pd.to_datetime(df.index).time 37 | df.set_index('date', inplace=True) 38 | 39 | return df 40 | 41 | 42 | def get_forecast(): 43 | df = get_finance_data() 44 | 45 | # Assuming that we've properly trained the model before and that the 46 | # hyperparameters are correctly tweaked, we use the full dataset to fit 47 | y = df['Low'].values 48 | model = ARIMA(y, order=(5,0,1)).fit() 49 | forecast = model.forecast(steps=1)[0] 50 | 51 | # Returning the last real data and the forecast for the next minute 52 | return (y[len(y)-1], forecast) 53 | 54 | 55 | def trade_robinhood(): 56 | timed_otp = pyotp.TOTP(RH_MFA_CODE).now() 57 | login = rh.login(RH_USER_EMAIL, RH_PASSWORD, mfa_code=timed_otp) 58 | 59 | last_real_data, forecast = get_forecast() 60 | 61 | # Your code to decide if you want to buy or sell 62 | # (and the number of shares) goes here 63 | action = 'BUY' # or 'SELL', or 'HOLD', or... 64 | shares = 1 65 | 66 | if action == 'BUY': 67 | rh.order_buy_market('GOOG', shares) 68 | return f'Bought {shares} shares.' 69 | elif action == 'SELL': 70 | rh.order_sell_market('GOOG', shares) 71 | return f'Sold {shares} shares.' 72 | else: 73 | return f'No shares were bought nor sold.' 74 | 75 | 76 | def trade_alpaca(): 77 | api = alpaca.REST(ALPACA_KEY_ID, ALPACA_SECRET_KEY, base_url=BASE_URL) 78 | 79 | last_real_data, forecast = get_forecast() 80 | 81 | # Your code to decide if you want to buy or sell 82 | # (and the number of shares) goes here 83 | action = 'BUY' # or 'SELL', or 'HOLD', or... 84 | shares = 1 85 | 86 | if action == 'BUY': 87 | api.submit_order(symbol='GOOG', qty=shares, side='buy', type='market', time_in_force='day') 88 | return f'Bought {shares} shares.' 89 | elif action == 'SELL': 90 | api.submit_order(symbol='GOOG', qty=shares, side='sell', type='market', time_in_force='day') 91 | return f'Sold {shares} shares.' 92 | else: 93 | return f'No shares were bought nor sold.' 94 | 95 | 96 | def send_message(event, context): 97 | action_performed = trade_alpaca() # or trade_robinhood() 98 | 99 | bot = telegram.Bot(token=TOKEN) 100 | bot.sendMessage(chat_id=CHAT_ID, text=action_performed) 101 | -------------------------------------------------------------------------------- /original_boilerplate/requirements.txt: -------------------------------------------------------------------------------- 1 | yfinance==0.1.55 2 | pandas==1.1.5 3 | numpy==1.19.4 4 | statsmodels==0.12.1 5 | pyotp==2.4.1 6 | robin-stocks==1.5.3 7 | matplotlib==3.3.3 8 | alpaca-trade-api==0.51.0 9 | python-telegram-bot==12.2.0 -------------------------------------------------------------------------------- /original_boilerplate/serverless.yml: -------------------------------------------------------------------------------- 1 | # Welcome to Serverless! 2 | # 3 | # This file is the main config file for your service. 4 | # It's very minimal at this point and uses default values. 5 | # You can always add more config options for more control. 6 | # We've included some commented out config examples here. 7 | # Just uncomment any of them to get that config option. 8 | # 9 | # For full config options, check the docs: 10 | # docs.serverless.com 11 | # 12 | # Happy Coding! 13 | 14 | service: ai-trading-system 15 | # app and org for use with dashboard.serverless.com 16 | #app: your-app-name 17 | #org: your-org-name 18 | 19 | # You can pin your service to only deploy with a specific Serverless version 20 | # Check out our docs for more details 21 | frameworkVersion: '2' 22 | 23 | provider: 24 | name: aws 25 | runtime: python3.8 26 | environment: 27 | TELEGRAM_TOKEN: ${env:TELEGRAM_TOKEN} 28 | # If using RobinHood 29 | RH_USER_EMAIL: ${env:RH_USER_EMAIL} 30 | RH_PASSWORD: ${env:RH_PASSWORD} 31 | RH_MFA_CODE: ${env:RH_MFA_CODE} 32 | # If using Alpaca 33 | ALPACA_KEY_ID: ${env:ALPACA_KEY_ID} 34 | ALPACA_SECRET_KEY: ${env:ALPACA_SECRET_KEY} 35 | 36 | functions: 37 | cron: 38 | handler: handler.send_message 39 | events: 40 | # Invoke Lambda function at 21:00 UTC every day 41 | - schedule: cron(00 21 * * ? *) 42 | 43 | --------------------------------------------------------------------------------