|
| 1 | +""" |
| 2 | +This is an example of how to use various functions/methods/classes in the repo. |
| 3 | +This is beyond not financial advice. |
| 4 | +This is for demonstration purposes only. |
| 5 | +Please do not ping me if you hook this chat-gpt-looking code up to a real brokerage account and just letterrip. |
| 6 | +""" |
| 7 | + |
| 8 | +import json |
| 9 | +from datetime import datetime, timedelta |
| 10 | +import pandas as pd |
| 11 | +import urllib.parse as urll |
| 12 | +from accounts import Accounts |
| 13 | +from api_client import APIClient |
| 14 | +from orders import Orders |
| 15 | +from market_data import Quotes |
| 16 | +from tqdm import tqdm |
| 17 | + |
| 18 | + |
| 19 | +def actually_do_some_trading(orders_api, account_hash, valid_quotes): |
| 20 | + traded_tickers = [] |
| 21 | + # Process valid trades |
| 22 | + for ticker, row in tqdm(valid_quotes.iterrows(), total=valid_quotes.shape[0], desc="Processing trades"): |
| 23 | + bid_price = row['bidPrice'] |
| 24 | + ask_price = row['askPrice'] |
| 25 | + last_price = row['lastPrice'] |
| 26 | + print(f"{ticker}") |
| 27 | + print(f"Bid price: {bid_price} | Ask price: {ask_price} | Last price: {last_price}") |
| 28 | + |
| 29 | + try: |
| 30 | + response = orders_api.place_order(account_hash=account_hash, |
| 31 | + symbol=ticker, |
| 32 | + side='BUY', |
| 33 | + quantity=6, |
| 34 | + order_type='LIMIT', |
| 35 | + limit_price=bid_price + 0.01, |
| 36 | + time_in_force='DAY') |
| 37 | + print(f"Order response: {response}") |
| 38 | + # write order number, ticker to algo_trades.json |
| 39 | + try: |
| 40 | + with open(f"algo_trades_{orders_api.client.config.initials}.json", "r") as f: |
| 41 | + data = json.load(f) |
| 42 | + except FileNotFoundError: |
| 43 | + data = [] |
| 44 | + data.append({"ticker": ticker, "order_number": response['order_number']}) |
| 45 | + with open(f"algo_trades_{orders_api.client.config.initials}.json", "w") as f: |
| 46 | + json.dump(data, f) |
| 47 | + traded_tickers.append(ticker) |
| 48 | + except Exception as e: |
| 49 | + print(f"Error placing order: {e}") |
| 50 | + return traded_tickers |
| 51 | + |
| 52 | + |
| 53 | +def find_trades_from_quotes(orders_api, quotes, account_hash): |
| 54 | + # Convert quotes to DataFrame |
| 55 | + quotes_df = pd.DataFrame.from_dict(quotes, orient='index') |
| 56 | + quotes_df.index = quotes_df.index.map(urll.unquote) |
| 57 | + |
| 58 | + # Extract relevant quote data |
| 59 | + quotes_df = quotes_df['quote'].apply(pd.Series) |
| 60 | + |
| 61 | + # Filter out quotes with missing data |
| 62 | + quotes_df = quotes_df.dropna(subset=['askPrice', 'askSize', 'bidPrice', 'bidSize', 'lastPrice']) |
| 63 | + |
| 64 | + # Apply trading logic |
| 65 | + valid_quotes = quotes_df[ |
| 66 | + (quotes_df['lastPrice'] >= 0.005) & |
| 67 | + (quotes_df['lastPrice'] <= 0.515) & |
| 68 | + ((quotes_df['askPrice'] - quotes_df['bidPrice']) >= 0.06) & |
| 69 | + (quotes_df['regular']['regularMarketLastPrice'] / (quotes_df['askPrice'] - quotes_df['bidPrice']) <= 10) & |
| 70 | + (quotes_df['askSize'] <= 100) & |
| 71 | + (quotes_df['bidSize'] <= 100) & |
| 72 | + ((quotes_df['lastPrice'] - quotes_df['bidPrice']) >= 0) & |
| 73 | + ((quotes_df['lastPrice'] - quotes_df['askPrice']) >= 0) & |
| 74 | + ((quotes_df['lastPrice'] - quotes_df['bidPrice']) <= 0.7 * (quotes_df['askPrice'] - quotes_df['bidPrice'])) & |
| 75 | + ((quotes_df['lastPrice'] - quotes_df['askPrice']) <= 0.7 * (quotes_df['askPrice'] - quotes_df['bidPrice'])) |
| 76 | + ] |
| 77 | + return valid_quotes |
| 78 | + |
| 79 | + |
| 80 | +def sell_the_algo_buys(orders_api, account_hash, quotes_api): |
| 81 | + # Check order statuses and handle new trades |
| 82 | + try: |
| 83 | + with open(f"algo_trades_{orders_api.client.config.initials}.json", "r") as f: |
| 84 | + data = json.load(f) |
| 85 | + except FileNotFoundError: |
| 86 | + data = [] |
| 87 | + data_tickers = [trade['ticker'] for trade in data] |
| 88 | + data_quotes = quotes_api.get_list(data_tickers) |
| 89 | + all_orders = orders_api.get_orders(account_hash=account_hash, |
| 90 | + maxResults=3000, |
| 91 | + fromEnteredTime=(datetime.now() - timedelta(days=360)).isoformat(timespec='seconds'), |
| 92 | + toEnteredTime=datetime.now().isoformat(timespec='seconds')) |
| 93 | + for trade in data: |
| 94 | + try: |
| 95 | + response = all_orders.get(trade['order_number']) |
| 96 | + print(f"Order status for {trade['ticker']}: {response['status']}") |
| 97 | + bought_price = response['price'] |
| 98 | + if response['status'] in ['FILLED', 'PARTIAL']: |
| 99 | + new_quote = data_quotes.get(trade['ticker']) |
| 100 | + new_quote_data = new_quote.get("quote") |
| 101 | + if new_quote_data: |
| 102 | + ask_price = new_quote_data.get('askPrice') |
| 103 | + if ask_price and bought_price <= ask_price - 0.03: |
| 104 | + response = orders_api.place_order(account_hash=account_hash, |
| 105 | + symbol=trade['ticker'], |
| 106 | + side='SELL', |
| 107 | + quantity=1, |
| 108 | + order_type='LIMIT', |
| 109 | + limit_price=ask_price - 0.01, |
| 110 | + time_in_force='DAY') |
| 111 | + print(f"Order response: {response}") |
| 112 | + print(f"Order response: {response}") |
| 113 | + except Exception as e: |
| 114 | + print(f"Error checking order status: {e}") |
| 115 | + |
| 116 | + |
| 117 | +def check_cash_account(account_api, account_hash): |
| 118 | + account = account_api.get_account(account_hash=account_hash, fields="positions") |
| 119 | + print(account) |
| 120 | + cash_account = account['cash'] |
| 121 | + return cash_account |
| 122 | + |
| 123 | + |
| 124 | +def main(): |
| 125 | + # Initialize client |
| 126 | + client = APIClient(initials="your_initials_here") |
| 127 | + accounts_api = Accounts(client) |
| 128 | + orders_api = Orders(client) |
| 129 | + quotes_api = Quotes(client) |
| 130 | + |
| 131 | + # Get account hash |
| 132 | + sample_account = client.account_numbers[0] |
| 133 | + account_hash = sample_account['hashValue'] |
| 134 | + |
| 135 | + # Check cash account |
| 136 | + if not check_cash_account(accounts_api, account_hash): |
| 137 | + print("Confirm pattern day trader status or using a cash account.") |
| 138 | + return |
| 139 | + |
| 140 | + # Get quotes |
| 141 | + quotes = quotes_api.get_list(["AAPL", "AMD", "TSLA", "MSFT", "GOOGL", "AMZN", "NFLX", "NVDA", "INTC", "CSCO"]) |
| 142 | + """ |
| 143 | + If you are wondering how to get a list of tickers that meet some given criteria, check out the get_finviz repo |
| 144 | + """ |
| 145 | + |
| 146 | + # Find trades |
| 147 | + find_trades_from_quotes(orders_api, quotes, account_hash) |
| 148 | + |
| 149 | + # Sell trades |
| 150 | + sell_the_algo_buys(orders_api, account_hash, quotes_api) |
0 commit comments