Created
June 7, 2020 17:06
-
-
Save ttamg/c1f2bff59ebd41e654c286d3a2d32018 to your computer and use it in GitHub Desktop.
Bot example (unsync to parallelise)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# UNSYNC VERSION - this parallelises both the run methods and | |
# then the API and database call methods within each run | |
import time | |
import random | |
import logging | |
from unsync import unsync | |
logging.basicConfig(format="%(asctime)s - %(message)s", level=logging.INFO) | |
@unsync # ADDED | |
def get_market_data(market): | |
""" | |
Calls the API and return data for a particular market | |
Likely steps: | |
1. Initialise the market data API and authenticate | |
2. Make a call to the API | |
3. Retry X times if response failed | |
4. Parse the response and return the market data | |
Returns: dict of market data | |
""" | |
logging.info(f"{market} - Started fetching market data.") | |
time.sleep(1) | |
logging.info(f"{market} - Finished fetching market data.") | |
return {"latest_price": 44.1, "volume": 1030} | |
@unsync # ADDED | |
def get_database_data(market): | |
""" | |
Fetches data about this market and our trading status from our database | |
Likely steps: | |
1. Initialise our database connection | |
2. Query database for our market data | |
3. Await response | |
4. Parse and return the database data | |
Returns: dict of database data | |
""" | |
logging.info(f"{market} - Started calling database.") | |
time.sleep(0.5) | |
logging.info(f"{market} - Finished fetching database data.") | |
return {"prices": [42, 41, 44, 45.5], "position": "long"} | |
def trade_logic(market, market_data, database_data): | |
""" | |
Makes decision on whether to trade given the latest market data and | |
information on current state and past prices (from our database) | |
Returns: 'go long', 'go short', 'exit position', None | |
""" | |
action = random.choice(["go long", "go short", "exit position", None]) | |
logging.info(f"{market} - Trading logic decision => {action}.") | |
return action | |
@unsync # ADDED | |
def execute_trade(market, action): | |
""" | |
Makes a trade via the API and responds once completed. | |
May have multiple retrys before raising exception if it failed. | |
Likely steps: | |
1. Initialise the trading API | |
2. Post trade to the API | |
3. Confirm success in response or retry if it failed | |
4. Return the response once successful | |
Returns: dict of trade_information or raises Exception | |
""" | |
logging.info(f"{market} - Posting {action} trade.") | |
time.sleep(5) | |
logging.info(f"{market} - {action} trade successful.") | |
return {"success": True, "trade_details": {}} | |
@unsync # ADDED | |
def update_database(market, market_data, trade): | |
""" | |
Updates the database data with the results of the recent trade and updated market data | |
Likely steps: | |
1. Post the new market data to the database | |
2. Post the trade if it exists to the database and update the market position | |
""" | |
logging.info(f"{market} - Started updating database.") | |
time.sleep(0.7) | |
logging.info(f"{market} - Finished updating database data.") | |
return True | |
@unsync # ADDED | |
def run(market): | |
""" | |
Run the bot cycle once now for a markets. | |
1. Reads market data from an API | |
2. Reads data from a database | |
3. (once both are available) Calculates some logic to decide on a trade | |
4. (if logic says we should trade) Executes a trade via an API | |
5. (when trade is completed) updates the database | |
Returns - action result of this cycle | |
""" | |
logging.critical(f"{market} - Starting the bot cycle.") | |
market_data = get_market_data(market) | |
database_data = get_database_data(market) | |
action = trade_logic( | |
market, market_data.result(), database_data.result() | |
) # ADDED .result() on inputs to await their results before calling trade_logic | |
if action is not None: | |
trade = execute_trade( | |
market, action | |
).result() # ADDED .result() to await result before moving on | |
else: | |
trade = None | |
logging.info(f"{market} - No trade to post.") | |
updates = update_database( | |
market, market_data, trade | |
).result() # ADDED .result() to await before moving on | |
logging.critical(f"{market} - Finished the bot cycle.") | |
return action | |
def run_all(): | |
""" | |
Run the bot cycle for all market. | |
Perhaps this method would be called by a cron job or similar to do every 5 minutes. | |
""" | |
logging.critical(f"Starting up the trading bot.") | |
start = time.time() | |
MARKETS = ["AAPL", "AMZN", "MSFT"] | |
trades = [] | |
for market in MARKETS: | |
action = run(market) | |
trades.append((market, action)) | |
logging.info( | |
f"Summary of trades: {[(trade[0], trade[1].result()) for trade in trades]}" | |
) # ADDED .result() to await result | |
logging.critical(f"Finished everything. Took {time.time() - start} seconds.") | |
if __name__ == "__main__": | |
run_all() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment