├── data_mining ├── READ_ME.md ├── twitter_sentiment.py ├── mine_trade.py └── mine.py ├── test_scripts ├── READ_ME.md ├── token_refresh.py ├── live_graph.py ├── sql_mgmt.py ├── create_files.py ├── sqlite_db_mgmt.c ├── iron_condor.py └── test_trade.py ├── visualize ├── READ_ME.md ├── profits.py └── randomwalk.py ├── data_processing ├── READ_ME.md ├── delete_duplicates.py └── organize.py ├── LICENSE └── README.md /data_mining/READ_ME.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test_scripts/READ_ME.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /visualize/READ_ME.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /data_processing/READ_ME.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /data_processing/delete_duplicates.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test_scripts/token_refresh.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from td.client import TDClient 3 | from datetime import datetime 4 | from td import exceptions 5 | import datetime 6 | import pandas as pd 7 | import sqlite3 8 | import time 9 | 10 | TDSession = TDClient( 11 | client_id='insert client id key', 12 | redirect_uri='https://127.0.0.1', 13 | credentials_path='path to working directory' 14 | ) 15 | 16 | TDSession.login() 17 | -------------------------------------------------------------------------------- /test_scripts/live_graph.py: -------------------------------------------------------------------------------- 1 | # code to be added to mine.py to display live paper/real trading 2 | # 3 | # 4 | 5 | import matplotlib.pyplot as plt 6 | import numpy as np 7 | 8 | X = np.linspace(0, 2, 1000) 9 | Y = X**2 + np.random.random(X.shape) 10 | go = True 11 | 12 | plt.ion() 13 | graph = plt.plot(X, Y)[0] 14 | 15 | while go: 16 | Y = X**2 + np.random.random(X.shape) 17 | graph.set_ydata(Y) 18 | plt.draw() 19 | plt.pause(3) 20 | 21 | 22 | -------------------------------------------------------------------------------- /visualize/profits.py: -------------------------------------------------------------------------------- 1 | 2 | import pandas as pd 3 | import numpy as np 4 | import matplotlib.pyplot as plt 5 | 6 | pd.set_option('display.max_rows', None) 7 | pd.set_option('display.max_columns', None) 8 | 9 | 10 | def graph_profits(excel_file): 11 | df = pd.read_excel(excel_file) 12 | u_dates = np.unique(df["bot_date"]) 13 | # df = df[df['Days_left'] != 0] 14 | # df = df[~df.C.str.split("_")[1].contains("P")] 15 | 16 | x = [x/10 for x in range(1, 200, 1)] 17 | y = [] 18 | yy = [] 19 | for i in x: 20 | tf = df[(df['bot_price'] < i)] 21 | #tf = tf[(tf['bot_price'] <= 2)] 22 | tf = tf[(tf['bot_date'] >= 20220305)] 23 | tf = tf[(tf['Days_left'] > 25)] 24 | # print(tf['Contract']) 25 | 26 | cost = round(np.sum(np.array(tf['bot_price'])) * 100, 3) 27 | y.append(cost) 28 | pl = round(np.sum(np.array(tf['TotalChange'])) * 100, 3) 29 | yy.append(pl) 30 | 31 | fig, axs = plt.subplots(2) 32 | 33 | axs[0].plot(x, y) 34 | axs[1].plot(x, yy) 35 | plt.show() 36 | 37 | return True 38 | 39 | 40 | graph_profits("portfolio_20220310.xlsx") 41 | 42 | 43 | # df = pd.read_csv("optionable.csv") 44 | # opt = np.array(df['Symbol']) 45 | # for i in opt: 46 | # if '\\xa0' in i: 47 | # print(i[4:]) 48 | # else: 49 | # print(i) 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, Drew Knapp 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /data_mining/twitter_sentiment.py: -------------------------------------------------------------------------------- 1 | from nltk.sentiment.vader import SentimentIntensityAnalyzer 2 | import tweepy 3 | import csv 4 | import pandas 5 | import time 6 | 7 | twitter_keys = tweepy.OAuthHandler('FEDY2PLyk64g7m7VddeF8FTd9', 'GGJlukrQHT1XV9BzWInL6vgVOq0Xy7T93YVoG4paSOZ6ayftKp') 8 | 9 | twitter_keys.set_access_token('973948809704366083-3nswKEYaZYllzJFkikfs6iVtyIZCBBN', 10 | 'Tlj2GdnSRQ7t4q1lMyyv3llPgs21b5bol48prqrpQcAff') 11 | 12 | access = tweepy.API(twitter_keys, wait_on_rate_limit=True, wait_on_rate_limit_notify=True) 13 | 14 | # write tweets to a csv file 15 | fileOpens = open("test.csv", 'a') 16 | fileWrite = csv.writer(fileOpens) 17 | 18 | arrTweets = [] 19 | numTweets = 0 20 | geoCode = "40.726673,-74.067391,30km" # geo code of dt Manhattan 21 | repeated = 0 22 | 23 | for tweet in tweepy.Cursor(access.search, q='covid19', 24 | count=10, 25 | lang="en", since="2020-04-09", 26 | ).items(): 27 | # for x in arrTweets: 28 | # if str(tweet) == str(x): 29 | # repeated += 1 30 | 31 | arrTweets.append(str(tweet)) 32 | numTweets += 1 33 | # print(numTweets) 34 | print(tweet.created_at, tweet.text) 35 | print() 36 | fileWrite.writerow([tweet.created_at, tweet.text.encode('utf-8')]) 37 | 38 | print(len(arrTweets)) 39 | 40 | sia = SentimentIntensityAnalyzer() 41 | num = 0 42 | 43 | for t in arrTweets: 44 | print(t) 45 | siaTweet = sia.polarity_scores(t) 46 | num += 1 47 | for n in sorted(siaTweet): 48 | print('{0}: {1}, '.format(n, siaTweet[n]), end='') 49 | print() 50 | # fileWrite.writerow('{0}: {1}, '.format(n, siaTweet[n]), end='') 51 | 52 | fileOpens.close() 53 | print(repeated) 54 | print(numTweets) 55 | print(num) 56 | -------------------------------------------------------------------------------- /test_scripts/sql_mgmt.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | import _sqlite3 3 | import matplotlib.pyplot as plt 4 | import numpy as np 5 | import pandas as pd 6 | 7 | conn = _sqlite3.connect('Options.db') 8 | c = conn.cursor() 9 | 10 | 11 | def test(): 12 | c.execute('SELECT * FROM puts WHERE rowid = 1') 13 | one = c.fetchone() 14 | 15 | for j in one: 16 | print(j) 17 | 18 | return 0 19 | 20 | 21 | # test() 22 | 23 | check, count = [], 0 24 | y_yes = [] 25 | 26 | for row in c.execute(f'SELECT quoteTimeInLong FROM puts WHERE symbol = \'AAPL_121120P123\''): 27 | for t in row: 28 | temp = int(t) // 100000 29 | # print(temp) 30 | check.append(temp) 31 | 32 | go = check[0] 33 | end = check[-1] 34 | 35 | x_time = np.arange(start=go, stop=end) 36 | 37 | for n in x_time: 38 | if n == check[count]: 39 | count = count + 1 40 | y_yes.append(1) 41 | else: 42 | y_yes.append(.5) 43 | 44 | 45 | def equa_distanced(): 46 | n_bins = [go] 47 | next_bin = go 48 | diff = (end - go) // 20 49 | count_2 = 0 50 | while count_2 < 20: 51 | n_bins.append(next_bin) 52 | next_bin = next_bin + diff 53 | print(next_bin) 54 | print(diff) 55 | count_2 = count_2 + 1 56 | 57 | return 0 58 | 59 | 60 | columns_wanted = ['time'] 61 | 62 | 63 | def make_sqlite_table(table_name): 64 | engine = create_engine('sqlite:///temp.db', echo=False) 65 | table_columns = pd.DataFrame(columns=columns_wanted) 66 | table_columns.to_sql(table_name, con=engine) 67 | 68 | return 0 69 | 70 | 71 | def add_rows(clean_data, table_name): 72 | engine = create_engine('sqlite:///temp.db', echo=False) 73 | clean_data.to_sql(table_name, con=engine, if_exists='append', index_label='index') 74 | 75 | return 0 76 | 77 | 78 | # make_sqlite_table('Time') 79 | # add_rows(check, 'Time') 80 | plt.hist(x=check, bins=173, density=False) 81 | plt.title('Minutes Captured') 82 | plt.show() 83 | conn.close() 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Options_Data_Science 2 | 3 | Disclosure: 4 | 5 | 1. Most files in this repo are under maintenance, REFER only to mine.py, token_refresh.py, test_trade.py 6 | 2. If you want stock data simultanously, run test_trade.py. it is not finished though 7 | 3. The file paths in my code work for MacOS, if on windows you will have to edit all the file paths 8 | 9 | Description: 10 | 11 | 1. mining - retrieve raw options data with TD ameritrade APIs - Directions bellow are for this 12 | 2. analyzing - researching trends and paper trading spreads 13 | 3. visualizing - graphing data and trading results with matplotlib and Tableau 14 | 15 | 16 | 17 | Directions: 18 | 19 | a) create a developer account on this link. https://developer.tdameritrade.com/apis. 20 | * Create/register an App 21 | 22 | 23 | b) pip install td-ameritrade-python-api 24 | 25 | 26 | c) run token_refresh.py to produce the td_state.json credentials file. 27 | YouTube video to help: skip to minute 22!! 28 | https://www.youtube.com/watch?v=8N1IxYXs4e8&t=1138s&ab_channel=SigmaCoding 29 | 30 | 31 | d) In your working directory make a 'Data' for data storage 32 | The tables created in mine.py will have the columns specified in the columns_wanted array. 33 | * If you want to remove a column, cut it out of columns_wanted and paste it in columns_unwanted. 34 | * If you want to add a column, cut it out of columns_unwated and paste it in columns_wanted. 35 | * All possible columns must be accounted for in both arrays. 36 | 37 | 38 | * In the stocks array, edit this list to collect options for any stock you want 39 | 40 | * in main(), change the argument in last_chain(#) to how many weeks of data u want. -> to_date = str(last_chain(5)) 41 | 42 | 43 | e) Run mine.py right before market opens. ~09:25 EST 44 | 45 | 46 | After getting familiar with the mine script, refer to test_trade how where to insert your own trading logic 47 | 48 | Future addons: 49 | 1) live trading 50 | 2) back testing 51 | 3) gui to activate and deactive different trading algos and keep track of paper portfolio 52 | 4) twitter sentiment 53 | 5) econmic models to predict market volatility 54 | 6) adding to a variety of different trading systems 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /test_scripts/create_files.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | import pandas as pd 3 | 4 | years = [2020, 2021] 5 | 6 | trade_days_2021 = {'jan': [4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 19, 20, 21, 22, 25, 26, 27, 28, 29], 7 | 'feb': [1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 16, 17, 18, 19, 22, 23, 24, 25, 26], 8 | 'mar': [1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 29, 30, 31], 9 | 'apr': [5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 26, 27, 28, 29, 30], 10 | 'may': [3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28], 11 | 'jun': [1, 2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 21, 22, 23, 24, 25, 28, 29, 30], 12 | 'jul': [1, 2, 6, 7, 8, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 26, 27, 28, 29, 30], 13 | 'aug': [2, 3, 4, 5, 6, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 23, 24, 25, 26, 27, 30, 31], 14 | 'sep': [1, 2, 3, 7, 8, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 27, 28, 29, 30], 15 | 'oct': [1, 4, 5, 6, 7, 8, 12, 13, 14, 15, 18, 19, 20, 21, 22, 25, 26, 27, 28, 29], 16 | 'nov': [1, 2, 3, 4, 5, 8, 9, 10, 12, 15, 16, 17, 18, 19, 22, 23, 24, 29, 30], 17 | 'dec': [1, 2, 3, 6, 7, 8, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 27, 28, 29, 30]} 18 | 19 | columns_wanted = ['putCall', 'symbol', 'exchangeName', 'bid', 'ask', 'last', 'highPrice', 20 | 'lowPrice', 'openPrice', 'closePrice', 'totalVolume', 'quoteTimeInLong', 21 | 'netChange', 'volatility', 'delta', 'gamma', 'theta', 'vega', 'rho', 'openInterest', 'timeValue', 22 | 'theoreticalVolatility', 'strikePrice', 'expirationDate', 'daysToExpiration', 'percentChange'] 23 | 24 | 25 | def make_sqlite_table(table_name, month, day, year): 26 | engine = create_engine(f'sqlite:///Data/Options_{month}{day}{year}.db', echo=False) 27 | table_columns = pd.DataFrame(columns=columns_wanted) 28 | table_columns.to_sql(table_name, con=engine) 29 | 30 | return 0 31 | 32 | 33 | for m in trade_days_2021: 34 | for d in trade_days_2021[m]: 35 | if d < 10: 36 | d = f'0{d}' 37 | make_sqlite_table('calls', m, d, years[1]) 38 | make_sqlite_table('puts', m, d, years[1]) 39 | -------------------------------------------------------------------------------- /test_scripts/sqlite_db_mgmt.c: -------------------------------------------------------------------------------- 1 | // 2 | // main.c 3 | // Options_db 4 | // 5 | // Created by Sato on 12/21/20. 6 | // 7 | 8 | #include 9 | #include 10 | 11 | int callback(void *, int, char **, char **); 12 | 13 | int main(void) 14 | { 15 | // Dec 2020 -> Dec 2021 16 | int days[13][24] = { 17 | {1,2,3,4,7,8,9,10,11,14,15,16,17,18,21,22,23}, 18 | {4,5,6,7,8,11,12,13,14,15,19,20,21,22,25,26,27,28,29}, 19 | {1,2,3,4,5,8,9,10,11,12,16,17,18,19,22,23,24,25,26}, 20 | {1,2,3,4,5,8,9,10,11,12,15,16,17,18,19,22,23,24,25,26,29,30,31}, 21 | {5,6,7,8,9,12,13,14,15,16,19,20,21,22,23,26,27,28,29,30}, 22 | {3,4,5,6,7,10,11,12,13,14,17,18,19,20,21,24,25,26,27,28}, 23 | {1,2,3,4,7,8,9,10,11,14,15,16,17,18,21,22,23,24,25,28,29,30}, 24 | {1,2,6,7,8,9,12,13,14,15,16,19,20,21,22,23,26,27,28,29,30}, 25 | {2,3,4,5,6,9,10,11,12,13,16,17,18,19,20,23,24,25,26,27,30,31}, 26 | {1,2,3,7,8,9,10,13,14,15,16,17,20,21,22,23,24,27,28,29,30}, 27 | {1,4,5,6,7,8,12,13,14,15,18,19,20,21,22,25,26,27,28,29}, 28 | {1,2,3,4,5,8,9,10,12,15,16,17,18,19,22,23,24,29,30}, 29 | {1,2,3,6,7,8,9,10,13,14,15,16,17,20,21,22,27,28,29,30} 30 | }; 31 | 32 | int current_day = days[0][16]; 33 | 34 | if(current_day > 0){ 35 | printf("here"); 36 | } 37 | 38 | sqlite3* db; 39 | char* err_msg = 0; 40 | 41 | int rc = sqlite3_open("/Users/Sato/Documents/PycharmProjects/Tsuru/Options_temp.db", &db); 42 | 43 | if (rc != SQLITE_OK) 44 | { 45 | fprintf(stderr, "Cnat connect: %s\n", sqlite3_errmsg(db)); 46 | sqlite3_close(db); 47 | 48 | return 1; 49 | } 50 | 51 | char* sql = "SELECT * FROM puts"; 52 | 53 | rc = sqlite3_exec(db, sql, callback, 0, &err_msg); 54 | 55 | if (rc != SQLITE_OK) 56 | { 57 | fprintf(stderr, "Failed to select data\n"); 58 | fprintf(stderr, "SQL error: %s\n", err_msg); 59 | 60 | sqlite3_free(err_msg); 61 | sqlite3_close(db); 62 | 63 | return 1; 64 | } 65 | sqlite3_close(db); 66 | 67 | return 0; 68 | } 69 | 70 | int callback(void* NotUsed, int argc, char **argv, char **azColName) 71 | { 72 | NotUsed = 0; 73 | 74 | for (int i = 0; i < argc; i++) 75 | { 76 | printf("%s,", argv[i]); 77 | // printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL"); 78 | 79 | } 80 | printf("\n"); 81 | 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /data_processing/organize.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | import sqlite3 3 | import os 4 | import pandas as pd 5 | 6 | # file_date = "" 7 | 8 | read_directory = '/Users/sato/PycharmProjects/open_interest/Data/' 9 | write_directory = '/Users/sato/PycharmProjects/open_interest/Data_Library/' 10 | substring = '_' 11 | 12 | columns = ['index', 'putCall', 'symbol', 'exchangeName', 'bid', 'ask', 'last', 13 | 'highPrice', 'lowPrice', 'openPrice', 'closePrice', 'totalVolume', 'quoteTimeInLong', 'netChange', 14 | 'volatility', 'delta', 'gamma', 'theta', 'vega', 'rho', 'openInterest', 'timeValue', 15 | 'theoreticalVolatility', 'strikePrice', 'expirationDate', 'daysToExpiration', 'percentChange'] 16 | 17 | 18 | def add_rows(clean_data, table_name, file_date): 19 | 20 | engine = create_engine(f'sqlite:///Data_Library/{file_date}', echo=False) 21 | clean_data.to_sql(table_name, con=engine, if_exists='append') 22 | 23 | return 0 24 | 25 | 26 | # sorting tickers is working but writing to new file is not 27 | for filename in os.listdir(read_directory): 28 | if filename.endswith(".db"): 29 | print(filename) 30 | con = sqlite3.connect(f'{read_directory}{filename}') 31 | df = pd.read_sql_query('''SELECT * FROM calls''', con) 32 | 33 | # df = df.drop(columns='index').to_numpy() 34 | df = df.to_numpy() 35 | temp_df = [] 36 | temp_equity = 0 37 | 38 | for i in df: 39 | if int(i[0]) == 0: 40 | if temp_equity: 41 | go_df = pd.DataFrame(temp_df, columns=columns) 42 | add_rows(go_df.drop(columns=['index']), f'c{temp_equity}', filename) 43 | temp_df = [] 44 | 45 | temp_df.append(i) 46 | temp_contract = i[2] 47 | temp_equity = temp_contract.partition(substring)[0] 48 | else: 49 | temp_df.append(i) 50 | 51 | for filename in os.listdir(read_directory): 52 | if filename.endswith(".db"): 53 | print(filename) 54 | con = sqlite3.connect(f'{read_directory}{filename}') 55 | df = pd.read_sql_query('''SELECT * FROM puts''', con) 56 | 57 | # df = df.drop(columns='index').to_numpy() 58 | df = df.to_numpy() 59 | temp_df = [] 60 | temp_equity = 0 61 | 62 | for i in df: 63 | if int(i[0]) == 0: 64 | if temp_equity: 65 | go_df = pd.DataFrame(temp_df, columns=columns) 66 | add_rows(go_df.drop(columns=['index']), f'p{temp_equity}', filename) 67 | temp_df = [] 68 | 69 | temp_df.append(i) 70 | temp_contract = i[2] 71 | temp_equity = temp_contract.partition(substring)[0] 72 | else: 73 | temp_df.append(i) 74 | -------------------------------------------------------------------------------- /test_scripts/iron_condor.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey, REAL 3 | from sqlalchemy.sql import text 4 | from sqlalchemy import inspect 5 | import matplotlib as plt 6 | import pandas as pd 7 | 8 | # full program is hidden, contact me for sample trader 9 | 10 | 11 | buying_power = 50000 12 | 13 | cart = [] 14 | 15 | columns = ['trade_id', 'openClose', 'time', 'daysLeft', 'outsideCall', 'insideCall', 16 | 'insidePut', 'outsidePut', 'quantity', 'costOutCall', 'costInCall', 17 | 'costInPut', 'costOutPut', 'total', 'debitCredit', 'width'] 18 | 19 | stocks = ['AAPL', 'AMZN', 'SPY', 'AMD', 'NVDA', 'NFLX', 'QQQ', 'ROKU'] 20 | 21 | current_data = [] 22 | 23 | for s in stocks: 24 | current_data.append(s) 25 | 26 | 27 | def make_sqlite_table(table_name): 28 | 29 | metadata = MetaData() 30 | trades = Table(f'{table_name}', metadata, 31 | Column('trade_id', Integer), 32 | Column('openClose', Integer), 33 | Column('time', Integer), 34 | Column('daysLeft', Integer), 35 | Column('outsideCall', String), 36 | Column('insideCall', String), 37 | Column('insidePut', String), 38 | Column('outsidePut', String), 39 | Column('quantity', Integer), 40 | Column('costOutCall', REAL), 41 | Column('costInCall', REAL), 42 | Column('costInPut', REAL), 43 | Column('costOutPut', REAL), 44 | Column('total', Integer), 45 | Column('debitCredit', Integer), 46 | Column('width', Integer)) 47 | 48 | engine = create_engine('sqlite:///Trades.db', echo=False) 49 | metadata.create_all(engine) 50 | 51 | inspector = inspect(engine) 52 | inspector.get_columns(f'{table_name}') 53 | 54 | return 0 55 | 56 | 57 | def add_rows(clean_data, table_name): 58 | 59 | engine = create_engine('sqlite:///Trades.db', echo=False) 60 | clean_data.to_sql(table_name, con=engine, if_exists='append', index_label='rowid') 61 | 62 | return 0 63 | 64 | 65 | def show_table(table_name): 66 | 67 | engine = create_engine('sqlite:///Trades.db', echo=False) 68 | with engine.connect() as con: 69 | 70 | rs = con.execute(f'SELECT * FROM {table_name}') 71 | for row in rs: 72 | print(row) 73 | 74 | return 0 75 | 76 | 77 | def delete_row(table_name, column, argument): 78 | 79 | engine = create_engine('sqlite:///Trades.db', echo=False) 80 | with engine.connect() as con: 81 | 82 | con.execute(f'DELETE FROM {table_name} WHERE {column}={argument}') 83 | 84 | return 0 85 | 86 | 87 | def buy_call(symbol, strikePrice, ask, quoteTimeInLong): 88 | 89 | return 0 90 | 91 | 92 | def buy_put(symbol, strikePrice, ask, quoteTimeInLong): 93 | 94 | return 0 95 | 96 | 97 | def sell_call(symbol, strikePrice, bid, quoteTimeInLong): 98 | 99 | return 0 100 | 101 | 102 | def sell_put(symbol, strikePrice, bid, quoteTimeInLong): 103 | 104 | return 0 105 | 106 | 107 | def open_iron_condor(): 108 | 109 | return 0 110 | 111 | 112 | def close_iron_condor(): 113 | 114 | return 0 115 | 116 | 117 | test_data = [[123, 1, 12321321321, 5, 110, 100, 90, 80, 1, 8.36, -10.30, -12.50, 118 | 9.20, -4.30, 0, 10]] 119 | 120 | test_data = pd.DataFrame(test_data, columns=columns) 121 | 122 | # make_sqlite_table('iron_condors') 123 | add_rows(test_data, 'iron_condors') 124 | show_table('iron_condors') 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /visualize/randomwalk.py: -------------------------------------------------------------------------------- 1 | # Trade options based off randomly generated stock movement with BSM 2 | 3 | from math import log, sqrt, exp 4 | from scipy.stats import norm 5 | import matplotlib.pyplot as plt 6 | import random 7 | import sqlite3 8 | 9 | start = 115 10 | price = start 11 | cash = 1000 12 | cash = int(cash) 13 | yesterday_cash = 0 14 | yesterday_price = start 15 | yesterday_IV = 0 16 | days = 0 17 | mood = 0 18 | 19 | net_liquid = 0 20 | commission = 0 21 | loot = 0 22 | 23 | calls_strikes = [] 24 | puts_strikes = [] 25 | calls = [] 26 | puts = [] 27 | strangles = [] 28 | option_ladder = [100, 101, 102.5, 104, 105, 106, 107.5, 108.75, 29 | 110, 111.25, 112.50, 113.75, 115, 116.25, 117.50, 30 | 118.75, 120, 121.25, 122.50, 123.75, 125, 126.25, 31 | 127.5, 128.75, 130] 32 | temp_c = 0 33 | temp_p = 0 34 | temp_total = 0 35 | tick_count = 0 36 | minutes_per_day = 390 37 | total_ticks = minutes_per_day 38 | total_dollar_movements = [] 39 | 40 | ticks = [] 41 | for i in range(total_ticks): 42 | ticks.append(i) 43 | 44 | 45 | # Call and Put classes using 2 different BSM implementations to value premium() 46 | class Call: 47 | 48 | def __init__(self, stock, strike, ttl, risk, sigma): 49 | self.stock = float(stock) 50 | self.strike = strike 51 | self.ttl = ttl 52 | self.risk = risk 53 | self.sigma = sigma 54 | self.d1num = (log(self.stock / self.strike) + (self.risk + .5 * self.sigma ** 2) * self.ttl) 55 | self.d1 = self.d1num / (self.sigma * sqrt(self.ttl)) 56 | self.d2 = self.d1 - self.sigma * sqrt(self.ttl) 57 | 58 | def premium(self): 59 | d1 = ((log(self.stock / self.strike) + 60 | (self.risk + 0.5 * self.sigma ** 2) * self.ttl) / 61 | (self.sigma * sqrt(self.ttl))) 62 | d2 = ((log(self.stock / self.strike) + 63 | (self.risk - 0.5 * self.sigma ** 2) * self.ttl) / 64 | (self.sigma * sqrt(self.ttl))) 65 | value = (self.stock * norm.cdf(d1, 0.0, 1.0) - 66 | self.strike * exp(-self.risk * self.ttl) * norm.cdf(d2, 0.0, 1.0)) 67 | return value 68 | 69 | def delta(self): 70 | delta = (norm.cdf(self.d1)) 71 | return delta 72 | 73 | def gamma(self): 74 | gamma = norm.pdf(self.d1) / (self.stock * self.sigma * sqrt(self.ttl)) 75 | return gamma 76 | 77 | def theta(self): 78 | theta = -(self.stock * norm.pdf(self.d1) * self.sigma / (2 * sqrt(self.ttl))) + (self.risk * self.strike) 79 | (self.risk * self.strike * exp(-self.risk * self.ttl) * norm.cdf(-self.d2)) 80 | return theta 81 | 82 | def vega(self): 83 | vega = (self.stock * norm.pdf(self.d1) * sqrt(self.ttl)) 84 | return vega 85 | 86 | 87 | class Put: 88 | 89 | def __init__(self, stock, strike, ttl, risk, sigma): 90 | self.stock = float(stock) 91 | self.strike = strike 92 | self.ttl = ttl 93 | self.risk = risk 94 | self.sigma = sigma 95 | self.d1num = (log(self.stock / self.strike) + (self.risk + .5 * self.sigma ** 2) * self.ttl) 96 | self.d1 = self.d1num / (self.sigma * sqrt(self.ttl)) 97 | self.d2 = self.d1 - self.sigma * sqrt(self.ttl) 98 | 99 | def premium(self): 100 | value = -self.stock * norm.cdf(-self.d1) + self.strike * exp(-self.risk * self.ttl) * norm.cdf(-self.d2) 101 | return value 102 | 103 | def delta(self): 104 | delta = -(norm.cdf(-self.d1)) 105 | return delta 106 | 107 | def gamma(self): 108 | gamma = norm.pdf(self.d1) / (self.stock * self.sigma * sqrt(self.ttl)) 109 | return gamma 110 | 111 | def theta(self): 112 | theta = -(self.stock * norm.pdf(self.d1) * self.sigma / (2 * sqrt(self.ttl))) + (self.risk * self.strike) 113 | (self.risk * self.strike * exp(-self.risk * self.ttl) * norm.cdf(-self.d2)) 114 | return theta 115 | 116 | def vega(self): 117 | vega = (self.stock * norm.pdf(self.d1) * sqrt(self.ttl)) 118 | return vega 119 | 120 | 121 | def lookup_call(p, cp): 122 | global temp_c, temp_total, net_liquid 123 | temp_call = Call(p, cp, 2 / 365, .08, .40) 124 | temp_c = float(format(temp_call.premium(), '.2f')) * 1000 125 | temp_total = temp_total + temp_c 126 | 127 | return temp_c 128 | 129 | 130 | def lookup_put(p, pp): 131 | global temp_p, temp_total, net_liquid 132 | temp_put = Put(p, pp, 2 / 365, .08, .40) 133 | # print(temp_put.delta()) 134 | temp_p = float(format(temp_put.premium(), '.2f')) * 1000 135 | temp_total = temp_total + temp_p 136 | 137 | return temp_p 138 | 139 | 140 | def buy_call(): 141 | plt.axvline(linewidth=1, color='g') 142 | 143 | global calls, cash, net_liquid, commission 144 | 145 | return 0 146 | 147 | 148 | def sell_call(): 149 | plt.axvline(linewidth=1, color='r') 150 | 151 | global cash, calls, net_liquid, commission 152 | 153 | return 0 154 | 155 | 156 | def buy_put(): 157 | plt.axvline(linewidth=1, color='b') 158 | 159 | global puts, cash, net_liquid, commission 160 | 161 | return 0 162 | 163 | 164 | def sell_put(): 165 | plt.axvline(linewidth=1, color='p') 166 | 167 | global puts, cash, net_liquid, commission 168 | 169 | return 0 170 | 171 | 172 | def buy_strangle(t, sp): 173 | plt.axvline(x=t, linewidth=1, color='orange') 174 | 175 | global calls, puts, cash, \ 176 | commission, strangles, option_ladder, \ 177 | temp_total, temp_c, temp_p, net_liquid, \ 178 | calls_strikes, puts_strikes 179 | 180 | call_strike = 0 181 | put_strike = 0 182 | k = 0 183 | 184 | while put_strike == 0: 185 | if option_ladder[k] > sp: 186 | call_strike = option_ladder[k + 1] 187 | calls_strikes.append(call_strike) 188 | put_strike = option_ladder[k - 1] 189 | puts_strikes.append(put_strike) 190 | k = k + 1 191 | 192 | temp_c = lookup_call(sp, call_strike) 193 | temp_p = lookup_put(sp, put_strike) 194 | temp_total = temp_c + temp_p 195 | net_liquid = net_liquid + temp_total 196 | 197 | calls.append(temp_c) 198 | puts.append(temp_p) 199 | strangles.append(temp_total) 200 | cash = cash - temp_c - temp_p - 1.30 201 | 202 | return 0 203 | 204 | 205 | # pull 25 puts and calls in a graph, numpy 206 | 207 | 208 | def sell_strangle(t, sp, pair, color): 209 | plt.axvline(x=t, linewidth=1, color=color) 210 | 211 | global calls, puts, cash, \ 212 | net_liquid, commission, \ 213 | temp_total, temp_c, temp_p, \ 214 | strangles, calls_strikes, puts_strikes 215 | 216 | temp_c = lookup_call(sp, calls_strikes[pair]) 217 | temp_p = lookup_put(sp, puts_strikes[pair]) 218 | temp_total = temp_c + temp_p 219 | 220 | cash = cash + temp_c + temp_p - 1.30 221 | net_liquid = net_liquid - calls[pair] - puts[pair] 222 | 223 | del calls[pair] 224 | del puts[pair] 225 | del strangles[pair] 226 | del calls_strikes[pair] 227 | del puts_strikes[pair] 228 | 229 | return 0 230 | 231 | 232 | def alert(a): 233 | global net_liquid, cash, strangles, \ 234 | temp_c, temp_p, temp_total, \ 235 | calls_strikes, puts_strikes 236 | 237 | if a == 0: 238 | print('Trade - Loss') 239 | 240 | elif a == 1: 241 | print('Trade - Win') 242 | 243 | elif a == 2: 244 | print('Trade - Scratch') 245 | 246 | elif a == 3: 247 | print('Trade - Buy') 248 | 249 | else: 250 | print('Check') 251 | 252 | print(f'|Time: {i} |#: {len(strangles)}|') 253 | print(f'|Call: {int(temp_c)} + Put: {int(temp_p)}| \n|Total: {int(temp_total)}|') 254 | if a == 3: 255 | print(f'|C strike: {calls_strikes[0]}| \n|P Strike: {puts_strikes[0]}|') 256 | 257 | print(f'|Net Liquidity: {int(net_liquid)}|') 258 | print(f'|Buying Power: {int(cash)}| \n') 259 | 260 | return 0 261 | 262 | 263 | def volatility(m): 264 | if m == 0: 265 | return random.uniform(-.00075, .0007) 266 | elif m == 1: 267 | return random.uniform(-.0007, .00075) 268 | else: 269 | return random.uniform(-.00075, .00075) 270 | 271 | 272 | d = 2 # change int for how many days to simulate 273 | while days < d: 274 | print('______________________________________________________') 275 | print(f'Day: {days + 1} \n') 276 | 277 | conn = sqlite3.connect('walk_training.db') 278 | con = conn.cursor() 279 | con.execute(''' SELECT count(name) FROM sqlite_master WHERE type='table' AND name='stocks' ''') 280 | 281 | # if the count is 1, then table exists 282 | if con.fetchone()[0] != 1: 283 | con.execute('CREATE TABLE stocks (date text, trans text, symbol text, qty real, price real)') 284 | 285 | yesterday_cash = cash 286 | yesterday_price = price 287 | 288 | prices = [] 289 | averages = [] 290 | total_dollar_movement = 0 291 | 292 | moods = [0] * 45 + [1] * 45 + [2] * 5 293 | moods = random.choice(moods) 294 | 295 | if moods == 0: 296 | plt.title('a random walk: Bear Day') 297 | 298 | elif moods == 1: 299 | plt.title('a random walk: Bull Day') 300 | 301 | else: 302 | plt.title('a random walk: Choppy Day') 303 | 304 | # con.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)") 305 | conn.commit() 306 | 307 | for i in range(total_ticks): 308 | change = volatility(moods) 309 | price = price + (price * change) 310 | prices.append(price) 311 | total_dollar_movement = total_dollar_movement + abs(change) 312 | temp_avg_total = 0 313 | 314 | 315 | denominator = min(len(prices), 50) 316 | 317 | 318 | averages.append(sum(prices[-denominator:]) / denominator) 319 | 320 | # if tick_count % 1 == 0 or tick_count == total_ticks - 1: 321 | 322 | if tick_count == 0: 323 | buy_strangle(0, price) 324 | alert(3) 325 | 326 | if len(strangles) > 0: 327 | temp_total = 0 328 | temp_c = lookup_call(price, calls_strikes[0]) 329 | temp_p = lookup_put(price, puts_strikes[0]) 330 | 331 | if temp_total < (strangles[0] - (strangles[0] * .15)): 332 | sell_strangle(tick_count, price, 0, 'r') 333 | alert(0) 334 | elif temp_total > (strangles[0] + (strangles[0] * .10)): 335 | sell_strangle(tick_count, price, 0, 'g') 336 | alert(1) 337 | elif tick_count == (total_ticks - 1): 338 | sell_strangle(total_ticks, price, 0, 'orange') 339 | alert(2) 340 | else: 341 | if tick_count != tick_count: 342 | alert(4) 343 | 344 | temp_total = 0 345 | 346 | tick_count = tick_count + 1 347 | 348 | total_dollar_movements.append(int(total_dollar_movement)) 349 | 350 | loot = loot + (cash - yesterday_cash) 351 | days = days + 1 352 | tick_count = 0 353 | print(f'Days left: {d - days} Total loot: {int(loot)} Total Moves: {int(total_dollar_movement)}') 354 | print('______________________________________________________') 355 | 356 | plt.plot(ticks, prices, label='AAPL') 357 | plt.plot(ticks, averages, label='movingAvg') 358 | plt.legend() 359 | plt.show() 360 | conn.close() 361 | 362 | ''' 363 | conn = sqlite3.connect('walk_training.db') 364 | con = conn.cursor() 365 | for row in con.execute('SELECT * FROM stocks ORDER BY price'): 366 | print(row) 367 | conn.close() 368 | ''' 369 | -------------------------------------------------------------------------------- /data_mining/mine_trade.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from td.client import TDClient 3 | from datetime import datetime 4 | from td import exceptions 5 | from requests.exceptions import ConnectionError 6 | import datetime 7 | import pandas as pd 8 | import sqlite3 9 | import time 10 | import credentials 11 | 12 | print("- Modules imported -") 13 | 14 | 15 | def make_sqlite_table(table_name): 16 | engine = create_engine('sqlite:///Options_temp.db', echo=False) 17 | table_columns = pd.DataFrame(columns=columns_wanted) 18 | table_columns.to_sql(table_name, con=engine) 19 | 20 | return 0 21 | 22 | 23 | def add_rows(clean_data, table_name): 24 | global file_date 25 | engine = create_engine(f'sqlite:///Data/Options_{file_date}.db', echo=False) 26 | clean_data.to_sql(table_name, con=engine, if_exists='append', index_label='index') 27 | 28 | return 0 29 | 30 | 31 | def delete_row(table_name, column, argument): 32 | conn = sqlite3.connect('Options.db') 33 | con = conn.cursor() 34 | con.execute(f'DELETE FROM {table_name} WHERE {column}={argument}') 35 | conn.commit() 36 | conn.close() 37 | 38 | return 0 39 | 40 | 41 | def delete_db_table(table_name): 42 | conn = sqlite3.connect('options.db') 43 | con = conn.cursor() 44 | con.execute(f'DROP TABLE {table_name}') 45 | conn.commit() 46 | conn.close() 47 | 48 | return 0 49 | 50 | 51 | def show_db_table(puts_calls): 52 | conn = sqlite3.connect('options.db') 53 | con = conn.cursor() 54 | for row in con.execute(f'SELECT * FROM {puts_calls}'): 55 | print(row) 56 | conn.close() 57 | 58 | return 0 59 | 60 | 61 | TDSession = TDClient( 62 | client_id=credentials.client_id, 63 | redirect_uri='https://127.0.0.1', 64 | credentials_path=credentials.json_path # Users/user/.../Project/td_state.json 65 | ) 66 | 67 | TDSession.login() 68 | print("- TD connection made -") 69 | 70 | 71 | def human_time(epoch): 72 | new_time = datetime.fromtimestamp(int(epoch) / 1000) 73 | output = new_time.strftime('%Y-%m-%d %H:%M:%S') 74 | 75 | return output 76 | 77 | 78 | def get_time_now(): 79 | curr_time = time.localtime() 80 | curr_clock = time.strftime("%H:%M:%S", curr_time) 81 | curr_m = time.strftime('%m') 82 | curr_y_d = time.strftime('%d%Y') 83 | 84 | int_curr_clock = int(f'{curr_clock[:2]}{curr_clock[3:5]}') 85 | 86 | return int_curr_clock, curr_m, curr_y_d 87 | 88 | 89 | def history(symbol): 90 | quotes = TDClient.get_price_history(TDSession, symbol=symbol, period_type='day', 91 | period=1, frequency_type='minute', frequency=1, 92 | extended_hours=False) 93 | # start_date = 1606086000000, end_date = 1606341600000, 94 | 95 | return quotes 96 | 97 | 98 | cur_weekly = 0 99 | cur_stocks = ['AAPL'] 100 | 101 | ''' 102 | test_quotes_2D = TDClient.get_quotes(TDSession, instruments=['AMD', 'AAPL']) 103 | 104 | 105 | def stats_list(): 106 | stats_wanted = ['symbol', 'bidPrice', 'bidSize', 'bidId', 'askPrice', 'askId', 107 | 'lastPrice', 'lastSize', 'lastId', 'openPrice', 'highPrice', 108 | 'lowPrice', 'bidTick', 'closePrice', 'netChange', 'totalVolume', 109 | 'quoteTimeInLong', 'tradeTimeInLong', 'exchange', 110 | 'exchangeName', 'volatility', 111 | 'regularMarketLastPrice', 'regularMarketNetChange', 112 | 'regularMarketTradeTimeInLong', 'netPercentChangeInDouble', 113 | 'markChangeInDouble', 'markPercentChangeInDouble', 114 | 'regularMarketPercentChangeInDouble'] 115 | 116 | output_stats = [] 117 | 118 | for key in test_quotes_2D['AMD'].keys(): 119 | for i in stats_wanted: 120 | if key == i: 121 | output_stats.append(key) 122 | 123 | return output_stats 124 | ''' 125 | 126 | file_date = 0 127 | 128 | trade_days_2021 = {'jan': [4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 19, 20, 21, 22, 25, 26, 27, 28, 29], 129 | 'feb': [1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 16, 17, 18, 19, 22, 23, 24, 25, 26], 130 | 'mar': [1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 29, 30, 31], 131 | 'apr': [5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 26, 27, 28, 29, 30], 132 | 'may': [3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28], 133 | 'jun': [1, 2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 21, 22, 23, 24, 25, 28, 29, 30], 134 | 'jul': [1, 2, 6, 7, 8, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 26, 27, 28, 29, 30], 135 | 'aug': [2, 3, 4, 5, 6, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 23, 24, 25, 26, 27, 30, 31], 136 | 'sep': [1, 2, 3, 7, 8, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 27, 28, 29, 30], 137 | 'oct': [1, 4, 5, 6, 7, 8, 12, 13, 14, 15, 18, 19, 20, 21, 22, 25, 26, 27, 28, 29], 138 | 'nov': [1, 2, 3, 4, 5, 8, 9, 10, 12, 15, 16, 17, 18, 19, 22, 23, 24, 29, 30], 139 | 'dec': [1, 2, 3, 6, 7, 8, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 27, 28, 29, 30]} 140 | 141 | opt_column_names = ['putCall', 'symbol', 'description', 'exchangeName', 'bid', 'ask', 'last', 'mark', 'bidSize', 142 | 'askSize', 'bidAskSize', 'lastSize', 'highPrice', 'lowPrice', 'openPrice', 'closePrice', 143 | 'totalVolume', 'tradeDate', 'tradeTimeInLong', 'quoteTimeInLong', 'netChange', 'volatility', 144 | 'delta', 'gamma', 'theta', 'vega', 'rho', 'openInterest', 'timeValue', 'theoreticalOptionValue', 145 | 'theoreticalVolatility', 'optionDeliverablesList', 'strikePrice', 'expirationDate', 146 | 'daysToExpiration', 147 | 'expirationType', 'lastTradingDay', 'multiplier', 'settlementType', 'deliverableNote', 148 | 'isIndexOption', 'percentChange', 'markChange', 'markPercentChange', 'mini', 'inTheMoney', 149 | 'nonStandard'] 150 | 151 | columns_unwanted = ['description', 'mark', 'bidSize', 'askSize', 'bidAskSize', 'lastSize', 'tradeDate', 152 | 'tradeTimeInLong', 'theoreticalOptionValue', 'optionDeliverablesList', 153 | 'expirationType', 'lastTradingDay', 'multiplier', 'settlementType', 'deliverableNote', 154 | 'isIndexOption', 'markChange', 'markPercentChange', 'nonStandard', 'inTheMoney', 'mini'] 155 | 156 | columns_wanted = ['putCall', 'symbol', 'exchangeName', 'bid', 'ask', 'last', 'highPrice', 157 | 'lowPrice', 'openPrice', 'closePrice', 'totalVolume', 'quoteTimeInLong', 158 | 'netChange', 'volatility', 'delta', 'gamma', 'theta', 'vega', 'rho', 'openInterest', 'timeValue', 159 | 'theoreticalVolatility', 'strikePrice', 'expirationDate', 'daysToExpiration', 'percentChange'] 160 | 161 | stocks = ['AAL', 'AAPL', 'AMD', 'AMZN', 'APA', 'ATVI', 'AXP', 'BABA', 'CME', 'CMG', 'CSCO', 162 | 'DAL', 'DIS', 'EA', 'FB', 'GME', 'GOOG', 'GS', 'HD', 'IBM', 'JNJ', 'JPM', 163 | 'MCD', 'MSFT', 'MU', 'NEE', 'NFLX', 'NVDA', 'ORCL', 'PEP', 'PYPL', 'QQQ', 'ROKU', 'SBUX', 164 | 'SNAP', 'SPY', 'SQ', 'TSLA', 'TWTR', 'ULTA', 'UPS', 'V', 'VXX', 'WMT', 'YUM', 165 | 'VDE', 'XLB', 'XLI', 'VCR', 'VDC', 'XLV', 'XLF', 'VGT', 'XLC', 'XLU', 'VNQ'] 166 | 167 | # This segment was used to sort out unique columns after i hard coded the columns i wanted 168 | ''' 169 | # print(len(opt_column_names)) 170 | # print(len(columns_unwanted)) 171 | # print(len(columns_wanted)) 172 | # print(len(stocks)) 173 | outs = [] 174 | 175 | 176 | def unique_list(n): 177 | output = [] 178 | 179 | for x in n: 180 | if x not in output: 181 | output.append(x) 182 | else: 183 | print(x) 184 | print(len(output)) 185 | 186 | return 0 187 | 188 | 189 | 190 | for i in opt_column_names: 191 | for j in columns_wanted: 192 | if i == j: 193 | outs.append(i) 194 | 195 | 196 | print(outs) 197 | print(len(outs)) 198 | unique_list(outs) 199 | ''' 200 | trade_stocks = ['AAPL', 'SPY', 'ROKU', 'TSLA', 'GME'] 201 | 202 | 203 | def get_weekly_data(clean): 204 | # get data for just the stuff we want to use 205 | for r in clean.iterrows(): 206 | if r[1][-2] == 'symbol': 207 | print(r[1]) 208 | if r[0] == 'bid': 209 | print(r[1]) 210 | print(r[1][2]) 211 | 212 | return 0 213 | 214 | 215 | def get_stock(stock): # pass an array of ticker(s) for stock 216 | stock_lookup = TDSession.get_quotes(instruments=stock) 217 | 218 | return stock_lookup 219 | 220 | 221 | def raw_stock(raw): 222 | clean_stock_data = [[]] 223 | 224 | for i in raw.keys(): 225 | print(i) 226 | 227 | return clean_stock_data 228 | 229 | 230 | def pandas_stock_data(arr): 231 | pandas_data = [] 232 | return pandas_data 233 | 234 | 235 | def get_next_stock(): 236 | global pulls 237 | global failed_pulls 238 | 239 | for stock in trade_stocks: 240 | error = False 241 | 242 | try: 243 | stock_data = get_stock(stock) 244 | 245 | except (exceptions.ServerError, exceptions.GeneralError, exceptions.ExdLmtError, ConnectionError): 246 | error = True 247 | failed_pulls = failed_pulls + 1 248 | print('A server error occurred') 249 | 250 | if not error: 251 | try: 252 | clean_stock_data = pandas_stock_data(raw_stock(stock_data)) 253 | # add_rows(clean_stock_data) UNCOMMENT TO ADD TO STOCKS.DB 254 | pulls = pulls + 1 255 | 256 | except ValueError: 257 | print(ValueError.with_traceback()) 258 | print(f'{stock} did not have values for this iteration') 259 | failed_pulls = failed_pulls + 1 260 | 261 | print(stock) 262 | time.sleep(1) 263 | return 0 264 | 265 | 266 | def get_chain(stock): 267 | opt_lookup = TDSession.get_options_chain( 268 | option_chain={'symbol': stock, 'strikeCount': 50, 269 | 'toDate': '2021-4-23'}) 270 | 271 | return opt_lookup 272 | 273 | 274 | def raw_chain(raw, put_call): 275 | cp = f'{put_call}ExpDateMap' 276 | clean_data = [[]] 277 | r = -1 278 | for k in raw[cp].keys(): 279 | # print(k, raw[k], '\n') 280 | for strike in raw[cp][k].keys(): 281 | # print(strike, raw[k][strike]) 282 | for a in raw[cp][k][strike][0].keys(): 283 | # if r == -1: 284 | # print(raw[cp][k][strike][0].keys()) 285 | unit = raw[cp][k][strike][0][a] 286 | if unit == put_call.upper(): 287 | r = r + 1 288 | if r > 0: 289 | clean_data.append([]) 290 | 291 | clean_data[r].append(unit) 292 | 293 | return clean_data 294 | 295 | 296 | def pandas_chain(clean): 297 | 298 | df_cp = pd.DataFrame(clean, columns=opt_column_names) 299 | panda_data = df_cp.drop(columns=columns_unwanted) 300 | 301 | return panda_data 302 | 303 | 304 | pulls = 0 305 | failed_pulls = 0 306 | 307 | 308 | def get_next_chains(): 309 | x = 0 310 | global pulls 311 | global failed_pulls 312 | global cur_stocks 313 | 314 | for stock in stocks: 315 | error = False 316 | 317 | try: 318 | chain = get_chain(stock) 319 | 320 | except (exceptions.ServerError, exceptions.GeneralError, exceptions.ExdLmtError, ConnectionError): 321 | error = True 322 | failed_pulls = failed_pulls + 1 323 | print('A server error occurred') 324 | 325 | if not error: 326 | try: 327 | clean = pandas_chain(raw_chain(chain, 'call')) 328 | add_rows(clean, 'calls') 329 | for s in cur_stocks: 330 | if s == stock: 331 | get_weekly_data(clean) 332 | pulls = pulls + 1 333 | 334 | except ValueError: 335 | print(ValueError.with_traceback()) 336 | print(f'{x}: Calls for {stock} did not have values for this iteration') 337 | failed_pulls = failed_pulls + 1 338 | 339 | try: 340 | get_clean = pandas_chain(raw_chain(chain, 'put')) 341 | add_rows(get_clean, 'puts') 342 | pulls = pulls + 1 343 | 344 | except ValueError: 345 | print(f'{x}: Puts for {stock} did not have values for this iteration') 346 | failed_pulls = failed_pulls + 1 347 | 348 | print(f'{x}: {stock}') 349 | x = x + 1 350 | time.sleep(2) 351 | 352 | return 0 353 | 354 | 355 | # |SQLite management| # 356 | # 357 | # make_sqlite_table('calls') # inputs: puts|calls 358 | # make_sqlite_table('puts') # inputs: puts|calls 359 | # delete_db_table('calls') 360 | # delete_db_table('puts') 361 | # show_db_table('calls') 362 | # show_db_table('puts') 363 | # add_rows(clean_chain(raw_chain(get_chain('SPY'), 'put')), 'puts') # raw_chain(,'put|call')), 'puts|calls') 364 | # delete_row('puts', '', 1321354652) 365 | 366 | 367 | def main(): 368 | global file_date 369 | global trade_stocks 370 | 371 | t, mon, day = get_time_now() 372 | mon = list(trade_days_2021.keys())[int(mon) - 1] 373 | ''' # uncomment for LIVE 374 | while True: 375 | if (t < 930) or (t > 1600): 376 | print(f'{t}: Market closed {mon}{day}'.upper()) 377 | time.sleep(10) 378 | else: 379 | break 380 | ''' 381 | # uncomment below line when TESTING on live data 382 | file_date = f'temp' 383 | # uncomment below line to save and analyze live data 384 | # file_date = f'{mon}{day}' 385 | 386 | pull_count = 0 387 | end_t = 1600 388 | 389 | while get_time_now()[0]: # < end_t: insert segment to run LIVE 390 | # get_next_stock() 391 | get_next_chains() 392 | pull_count = pull_count + 1 393 | print(pull_count) 394 | 395 | print('option market closed') 396 | print(f'failed_pulls: {failed_pulls}') 397 | print(f'pulls: {pulls}') 398 | 399 | return 0 400 | 401 | 402 | main() 403 | -------------------------------------------------------------------------------- /test_scripts/test_trade.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from td.client import TDClient 3 | from datetime import datetime 4 | from td import exceptions 5 | from requests.exceptions import ConnectionError 6 | import datetime 7 | import pandas as pd 8 | import sqlite3 9 | import time 10 | import credentials 11 | 12 | print("- Modules imported -") 13 | 14 | 15 | def make_sqlite_table(table_name): 16 | engine = create_engine('sqlite:///Options_temp.db', echo=False) 17 | table_columns = pd.DataFrame(columns=columns_wanted) 18 | table_columns.to_sql(table_name, con=engine) 19 | 20 | return 0 21 | 22 | 23 | def add_rows(clean_data, table_name): 24 | global file_date 25 | engine = create_engine(f'sqlite:///Data/Options_{file_date}.db', echo=False) 26 | clean_data.to_sql(table_name, con=engine, if_exists='append', index_label='index') 27 | 28 | return 0 29 | 30 | 31 | def delete_row(table_name, column, argument): 32 | conn = sqlite3.connect('Options.db') 33 | con = conn.cursor() 34 | con.execute(f'DELETE FROM {table_name} WHERE {column}={argument}') 35 | conn.commit() 36 | conn.close() 37 | 38 | return 0 39 | 40 | 41 | def delete_db_table(table_name): 42 | conn = sqlite3.connect('options.db') 43 | con = conn.cursor() 44 | con.execute(f'DROP TABLE {table_name}') 45 | conn.commit() 46 | conn.close() 47 | 48 | return 0 49 | 50 | 51 | def show_db_table(puts_calls): 52 | conn = sqlite3.connect('options.db') 53 | con = conn.cursor() 54 | for row in con.execute(f'SELECT * FROM {puts_calls}'): 55 | print(row) 56 | conn.close() 57 | 58 | return 0 59 | 60 | 61 | TDSession = TDClient( 62 | client_id=credentials.client_id, 63 | redirect_uri=credentials.refresh_url, 64 | credentials_path=credentials.json_path 65 | ) 66 | 67 | TDSession.login() 68 | print("- TD connection made -") 69 | 70 | 71 | def human_time(epoch): 72 | new_time = datetime.fromtimestamp(int(epoch) / 1000) 73 | output = new_time.strftime('%Y-%m-%d %H:%M:%S') 74 | 75 | return output 76 | 77 | 78 | def get_time_now(): 79 | curr_time = time.localtime() 80 | curr_clock = time.strftime("%H:%M:%S", curr_time) 81 | curr_m = time.strftime('%m') 82 | curr_y_d = time.strftime('%d%Y') 83 | 84 | int_curr_clock = int(f'{curr_clock[:2]}{curr_clock[3:5]}') 85 | 86 | return int_curr_clock, curr_m, curr_y_d 87 | 88 | 89 | # get historical averages # 90 | # Start # 91 | ''' 92 | Example: For a 2 day / 1 min chart, the values would be: 93 | period: 2 94 | periodType: day 95 | frequency: 1 96 | frequencyType: min 97 | 98 | Valid periods by periodType (defaults marked with an asterisk): 99 | day: 1, 2, 3, 4, 5, 10* 100 | month: 1*, 2, 3, 6 101 | year: 1*, 2, 3, 5, 10, 15, 20 102 | ytd: 1* 103 | ''' 104 | 105 | 106 | def history(symbol, period, p_type, freq, f_type): 107 | quotes = TDClient.get_price_history(TDSession, symbol=symbol, 108 | period=period, period_type=p_type, 109 | frequency=freq, frequency_type=f_type, 110 | extended_hours=False, start_date=1606086000000) 111 | # start_date=1606086000000, end_date = 1606341600000, 112 | 113 | return quotes 114 | 115 | 116 | five_day_avg, five_cnt = 0, 0 117 | thirty_day_avg, thirty_cnt = 0, 0 118 | sixty_day_avg, sixty_cnt = 0, 0 119 | 120 | # print(history('SPY')) 121 | five_history = history('SPY', 5, 'day', 1, 'minute') 122 | # thirty_history = history('SPY', 30, 'day', 1, 'minute') 123 | # sixty_history = history('SPY', 60, 'day', 1, 'minute') 124 | 125 | for i in five_history['candles']: 126 | five_cnt = five_cnt + 1 127 | five_day_avg = (five_day_avg + i) / five_cnt 128 | print(i['open']) 129 | # print(len(history('SPY'))) 130 | # End # 131 | 132 | cur_weekly = 0 133 | file_date = 0 134 | 135 | pulls = 0 136 | failed_pulls = 0 137 | 138 | trade_days_2021 = {'jan': [4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 19, 20, 21, 22, 25, 26, 27, 28, 29], 139 | 'feb': [1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 16, 17, 18, 19, 22, 23, 24, 25, 26], 140 | 'mar': [1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 29, 30, 31], 141 | 'apr': [5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 26, 27, 28, 29, 30], 142 | 'may': [3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28], 143 | 'jun': [1, 2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 21, 22, 23, 24, 25, 28, 29, 30], 144 | 'jul': [1, 2, 6, 7, 8, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 26, 27, 28, 29, 30], 145 | 'aug': [2, 3, 4, 5, 6, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 23, 24, 25, 26, 27, 30, 31], 146 | 'sep': [1, 2, 3, 7, 8, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 27, 28, 29, 30], 147 | 'oct': [1, 4, 5, 6, 7, 8, 12, 13, 14, 15, 18, 19, 20, 21, 22, 25, 26, 27, 28, 29], 148 | 'nov': [1, 2, 3, 4, 5, 8, 9, 10, 12, 15, 16, 17, 18, 19, 22, 23, 24, 29, 30], 149 | 'dec': [1, 2, 3, 6, 7, 8, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 27, 28, 29, 30]} 150 | 151 | opt_column_names = ['putCall', 'symbol', 'description', 'exchangeName', 'bid', 'ask', 'last', 'mark', 'bidSize', 152 | 'askSize', 'bidAskSize', 'lastSize', 'highPrice', 'lowPrice', 'openPrice', 'closePrice', 153 | 'totalVolume', 'tradeDate', 'tradeTimeInLong', 'quoteTimeInLong', 'netChange', 'volatility', 154 | 'delta', 'gamma', 'theta', 'vega', 'rho', 'openInterest', 'timeValue', 'theoreticalOptionValue', 155 | 'theoreticalVolatility', 'optionDeliverablesList', 'strikePrice', 'expirationDate', 156 | 'daysToExpiration', 157 | 'expirationType', 'lastTradingDay', 'multiplier', 'settlementType', 'deliverableNote', 158 | 'isIndexOption', 'percentChange', 'markChange', 'markPercentChange', 'mini', 'inTheMoney', 159 | 'nonStandard'] 160 | 161 | columns_unwanted = ['description', 'mark', 'bidSize', 'askSize', 'bidAskSize', 'lastSize', 'tradeDate', 162 | 'tradeTimeInLong', 'theoreticalOptionValue', 'optionDeliverablesList', 163 | 'expirationType', 'lastTradingDay', 'multiplier', 'settlementType', 'deliverableNote', 164 | 'isIndexOption', 'markChange', 'markPercentChange', 'nonStandard', 'inTheMoney', 'mini'] 165 | 166 | columns_wanted = ['putCall', 'symbol', 'exchangeName', 'bid', 'ask', 'last', 'highPrice', 167 | 'lowPrice', 'openPrice', 'closePrice', 'totalVolume', 'quoteTimeInLong', 168 | 'netChange', 'volatility', 'delta', 'gamma', 'theta', 'vega', 'rho', 'openInterest', 'timeValue', 169 | 'theoreticalVolatility', 'strikePrice', 'expirationDate', 'daysToExpiration', 'percentChange'] 170 | 171 | stocks = ['AAL', 'AAPL', 'AMD', 'AMZN', 'APA', 'ATVI', 'AXP', 'BABA', 'CME', 'CMG', 'CSCO', 172 | 'DAL', 'DIS', 'EA', 'FB', 'GME', 'GOOG', 'GS', 'HD', 'IBM', 'JNJ', 'JPM', 173 | 'MCD', 'MSFT', 'MU', 'NEE', 'NFLX', 'NVDA', 'ORCL', 'PEP', 'PYPL', 'QQQ', 'ROKU', 'SBUX', 174 | 'SNAP', 'SPY', 'SQ', 'TSLA', 'TWTR', 'ULTA', 'UPS', 'V', 'VXX', 'WMT', 'YUM', 175 | 'VDE', 'XLB', 'XLI', 'VCR', 'VDC', 'XLV', 'XLF', 'VGT', 'XLC', 'XLU', 'VNQ'] 176 | 177 | trade_stocks = ['SPY'] 178 | 179 | 180 | def get_weekly_data(clean): 181 | # get data for just the stuff we want to use 182 | for r in clean.iterrows(): 183 | if r[1][-2] == 'symbol': 184 | print(r[1]) 185 | if r[0] == 'bid': 186 | print(r[1]) 187 | print(r[1][2]) 188 | 189 | return 0 190 | 191 | 192 | # Following 4 functions retrieve, clean, and process stock data 193 | 194 | 195 | def get_stocks(tickers): # pass an array of ticker(s) for stock 196 | raw_data = TDSession.get_quotes(instruments=tickers) 197 | 198 | return raw_data 199 | 200 | 201 | def raw_stock(raw): 202 | clean_stock_data = [[]] 203 | 204 | for stonk, data in raw.items(): 205 | if stonk == 'SPY': 206 | for attr, v in data.items(): 207 | if attr == 'totalVolume': 208 | print(v) 209 | # BOOKMARK ~~~~~~~~~~~ move this logic to get_next_stocks() 210 | cur_calls = clean_chain(raw_chain(get_chain(stonk), 'call')) 211 | print(cur_calls['daysToExpiration'].unique()) 212 | call_df = cur_calls.loc[cur_calls['daysToExpiration'] < 9] 213 | #print(call_df) 214 | cur_puts = clean_chain(raw_chain(get_chain(stonk), 'put')) 215 | put_df = cur_puts.loc[cur_puts['daysToExpiration'] < 7] 216 | #print(put_df) 217 | 218 | return clean_stock_data 219 | 220 | 221 | def get_next_stocks(): 222 | global pulls 223 | global failed_pulls 224 | 225 | for s in trade_stocks: 226 | error = False 227 | 228 | try: 229 | stock_data = get_stocks([s]) 230 | 231 | except (exceptions.ServerError, exceptions.GeneralError, exceptions.ExdLmtError, ConnectionError): 232 | error = True 233 | failed_pulls = failed_pulls + 1 234 | print('A server error occurred') 235 | 236 | if not error: 237 | try: 238 | clean_stock_data = raw_stock(stock_data) 239 | # add_rows(clean_stock_data) UNCOMMENT TO ADD TO STOCKS.DB 240 | pulls = pulls + 1 241 | 242 | except ValueError: 243 | print(ValueError.with_traceback()) 244 | print(f'{s} did not have values for this iteration') 245 | failed_pulls = failed_pulls + 1 246 | 247 | return 0 248 | 249 | 250 | # Following 4 functions retrieve, clean, and process option chains 251 | 252 | 253 | def get_chain(stock): 254 | opt_lookup = TDSession.get_options_chain( 255 | option_chain={'symbol': stock, 'strikeCount': 5, 256 | 'toDate': '2021-2-26'}) 257 | 258 | return opt_lookup 259 | 260 | 261 | def raw_chain(raw, put_call): 262 | cp = f'{put_call}ExpDateMap' 263 | clean_data = [[]] 264 | r = -1 265 | for k in raw[cp].keys(): 266 | for strike in raw[cp][k].keys(): 267 | for a in raw[cp][k][strike][0].keys(): 268 | 269 | unit = raw[cp][k][strike][0][a] 270 | if unit == put_call.upper(): 271 | r = r + 1 272 | if r > 0: 273 | clean_data.append([]) 274 | 275 | clean_data[r].append(unit) 276 | 277 | return clean_data 278 | 279 | 280 | def clean_chain(clean): 281 | 282 | df_cp = pd.DataFrame(clean, columns=opt_column_names) 283 | panda_data = df_cp.drop(columns=columns_unwanted) 284 | 285 | return panda_data 286 | 287 | 288 | def get_next_chains(): 289 | x = 0 290 | global pulls 291 | global failed_pulls 292 | 293 | for stock in stocks: 294 | error = False 295 | try: 296 | chain = get_chain(stock) 297 | except (exceptions.ServerError, exceptions.GeneralError, exceptions.ExdLmtError): 298 | error = True 299 | failed_pulls = failed_pulls + 1 300 | print('A server error occurred') 301 | 302 | if not error: 303 | try: 304 | working_call_data = clean_chain(raw_chain(chain, 'call')) 305 | add_rows(working_call_data, 'calls') 306 | 307 | # print(working_call_data) UNCOMMENT to see working call data 308 | 309 | pulls = pulls + 1 310 | 311 | except ValueError: 312 | print(f'{x}: Calls for {stock} did not have values for this iteration') 313 | failed_pulls = failed_pulls + 1 314 | 315 | try: 316 | working_put_data = clean_chain(raw_chain(chain, 'put')) 317 | add_rows(working_put_data, 'puts') 318 | 319 | # print(working_put_data) UNCOMMENT to see working put data 320 | 321 | pulls = pulls + 1 322 | 323 | except ValueError: 324 | print(f'{x}: Puts for {stock} did not have values for this iteration') 325 | failed_pulls = failed_pulls + 1 326 | 327 | # -------------------------------------------------------------------------- 328 | # pseudo code for your own trading/analysis function calls 329 | # -------------------------------------------------------------------------- 330 | ''' pseudo examples what to do with the data each iteration 331 | with working_call_data: 332 | check_portfolio() 333 | update_portfolio_values() 334 | buy_vertical_call_spread() 335 | analyze_weekly_chain() 336 | buy_call() 337 | sell_call() 338 | buy_vertical_call_spread() 339 | 340 | with working_put_data: 341 | analyze_week(create_order(iron_condor(...))) 342 | submit_order(...) 343 | analyze_week(get_contract_moving_avg('call', 'AAPL_021221C130')) 344 | show_portfolio() 345 | ''' 346 | # -------------------------------------------------------------------------- 347 | # create and call your own framework 348 | # --------------------------------------------------------------------------- 349 | 350 | print(f'{x}: {stock}') 351 | x = x + 1 352 | time.sleep(2) 353 | 354 | return 0 355 | 356 | 357 | def main(): 358 | global file_date 359 | global trade_stocks 360 | 361 | t, mon, day = get_time_now() 362 | month = list(trade_days_2021.keys())[int(mon) - 1] 363 | ''' # uncomment for LIVE 364 | while True: 365 | if (t < 930) or (t > 1600): 366 | print(f'{t}: Market closed {month}{day}'.upper()) 367 | time.sleep(10) 368 | else: 369 | break 370 | ''' 371 | # uncomment below line when TESTING on live data 372 | file_date = f'temp' 373 | # uncomment below line to save and analyze live data 374 | # file_date = f'{month}{day}' 375 | 376 | pull_count = 0 377 | end_t = 2300 378 | 379 | while get_time_now()[0]: 380 | get_next_stocks() 381 | # get_next_chains() 382 | pull_count = pull_count + 1 383 | print(pull_count) 384 | time.sleep(1) 385 | 386 | print('option market closed') 387 | print(f'failed_pulls: {failed_pulls}') 388 | print(f'pulls: {pulls}') 389 | 390 | return 0 391 | 392 | 393 | main() 394 | 395 | 396 | # |SQLite management| # 397 | # 398 | # make_sqlite_table('calls') # inputs: puts|calls 399 | # make_sqlite_table('puts') # inputs: puts|calls 400 | # delete_db_table('calls') 401 | # delete_db_table('puts') 402 | # show_db_table('calls') 403 | # show_db_table('puts') 404 | # add_rows(clean_chain(raw_chain(get_chain('SPY'), 'put')), 'puts') # raw_chain(,'put|call')), 'puts|calls') 405 | # delete_row('puts', '', 1321354652) 406 | -------------------------------------------------------------------------------- /data_mining/mine.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from td.client import TDClient 3 | from datetime import datetime 4 | from datetime import date 5 | from td import exceptions 6 | import pandas as pd 7 | import sqlite3 8 | import time 9 | import credentials 10 | 11 | 12 | TDSession = TDClient( 13 | client_id=credentials.client_id, 14 | redirect_uri='https://127.0.0.1', 15 | credentials_path=credentials.json_path 16 | ) 17 | 18 | TDSession.login() 19 | 20 | 21 | def history(symbol): 22 | quotes = TDClient.get_price_history(TDSession, symbol=symbol, period_type='day', 23 | period=1, frequency_type='minute', frequency=1, 24 | extended_hours=False) 25 | # start_date = 1606086000000, end_date = 1606341600000, 26 | 27 | return quotes 28 | 29 | 30 | def make_sqlite_table(table_name): 31 | engine = create_engine('sqlite:///Data/Options.db', echo=False) 32 | table_columns = pd.DataFrame(columns=columns_wanted) 33 | table_columns.to_sql(table_name, con=engine) 34 | 35 | return 0 36 | 37 | 38 | def add_rows(clean_data, table_name): 39 | global file_date 40 | engine = create_engine(f'sqlite:///Data/Options_{file_date}.db', echo=False) 41 | clean_data.to_sql(table_name, con=engine, if_exists='append', index_label='index') 42 | 43 | return 0 44 | 45 | 46 | def delete_row(table_name, column, argument): 47 | conn = sqlite3.connect('Options.db') 48 | con = conn.cursor() 49 | con.execute(f'DELETE FROM {table_name} WHERE {column}={argument}') 50 | conn.commit() 51 | conn.close() 52 | 53 | return 0 54 | 55 | 56 | def delete_db_table(table_name): 57 | conn = sqlite3.connect('options.db') 58 | con = conn.cursor() 59 | con.execute(f'DROP TABLE {table_name}') 60 | conn.commit() 61 | conn.close() 62 | 63 | return 0 64 | 65 | 66 | def show_db_table(puts_calls): 67 | conn = sqlite3.connect('options.db') 68 | con = conn.cursor() 69 | for row in con.execute(f'SELECT * FROM {puts_calls}'): 70 | print(row) 71 | conn.close() 72 | 73 | return 0 74 | 75 | 76 | file_date = 0 77 | to_date = 0 78 | 79 | trade_days_2021 = {'jan': [4, 5, 6, 7, 8, 11, 12, 13, 14, 15, 19, 20, 21, 22, 25, 26, 27, 28, 29], 80 | 'feb': [1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 16, 17, 18, 19, 22, 23, 24, 25, 26], 81 | 'mar': [1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 29, 30, 31], 82 | 'apr': [5, 6, 7, 8, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 26, 27, 28, 29, 30], 83 | 'may': [3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 24, 25, 26, 27, 28], 84 | 'jun': [1, 2, 3, 4, 7, 8, 9, 10, 11, 14, 15, 16, 17, 18, 21, 22, 23, 24, 25, 28, 29, 30], 85 | 'jul': [1, 2, 6, 7, 8, 9, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 26, 27, 28, 29, 30], 86 | 'aug': [2, 3, 4, 5, 6, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 23, 24, 25, 26, 27, 30, 31], 87 | 'sep': [1, 2, 3, 7, 8, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 23, 24, 27, 28, 29, 30], 88 | 'oct': [1, 4, 5, 6, 7, 8, 12, 13, 14, 15, 18, 19, 20, 21, 22, 25, 26, 27, 28, 29], 89 | 'nov': [1, 2, 3, 4, 5, 8, 9, 10, 12, 15, 16, 17, 18, 19, 22, 23, 24, 29, 30], 90 | 'dec': [1, 2, 3, 6, 7, 8, 9, 10, 13, 14, 15, 16, 17, 20, 21, 22, 27, 28, 29, 30]} 91 | 92 | 93 | opt_column_names = ['putCall', 'symbol', 'description', 'exchangeName', 'bid', 'ask', 'last', 'mark', 'bidSize', 94 | 'askSize', 'bidAskSize', 'lastSize', 'highPrice', 'lowPrice', 'openPrice', 'closePrice', 95 | 'totalVolume', 'tradeDate', 'tradeTimeInLong', 'quoteTimeInLong', 'netChange', 'volatility', 96 | 'delta', 'gamma', 'theta', 'vega', 'rho', 'openInterest', 'timeValue', 'theoreticalOptionValue', 97 | 'theoreticalVolatility', 'optionDeliverablesList', 'strikePrice', 'expirationDate', 98 | 'daysToExpiration', 99 | 'expirationType', 'lastTradingDay', 'multiplier', 'settlementType', 'deliverableNote', 100 | 'isIndexOption', 'percentChange', 'markChange', 'markPercentChange', 'mini', 'inTheMoney', 101 | 'nonStandard'] 102 | 103 | columns_unwanted = ['description', 'mark', 'bidSize', 'askSize', 'bidAskSize', 'lastSize', 'tradeDate', 104 | 'tradeTimeInLong', 'theoreticalOptionValue', 'optionDeliverablesList', 105 | 'expirationType', 'lastTradingDay', 'multiplier', 'settlementType', 'deliverableNote', 106 | 'isIndexOption', 'markChange', 'markPercentChange', 'nonStandard', 'inTheMoney', 'mini'] 107 | 108 | columns_wanted = ['putCall', 'symbol', 'exchangeName', 'bid', 'ask', 'last', 'highPrice', 109 | 'lowPrice', 'openPrice', 'closePrice', 'totalVolume', 'quoteTimeInLong', 110 | 'netChange', 'volatility', 'delta', 'gamma', 'theta', 'vega', 'rho', 'openInterest', 'timeValue', 111 | 'theoreticalVolatility', 'strikePrice', 'expirationDate', 'daysToExpiration', 'percentChange'] 112 | 113 | stocks = ['AAPL', 'AMD', 'AMZN', 'TSLA', 'MU', 'NVDA', 'GOOG', 'ROKU', 'NFLX', 'FB', 'CMG', 'GME', 'MCD', 'SNAP'] 114 | 115 | ''' ~4700 stocks to add to stock list 116 | 117 | ['A', 'AA', 'AACQ', 'AAIC', 'AAL', 'AAN', 'AAOI', 'AAON', 'AAP', 'AAPL', 'AAT', 'AAU', 'AAWW', 'AAXJ', 'AB', 'ABB', 118 | 'ABBV', 'ABC', 'ABCB', 'ABEO', 'ABEV', 'ABG', 'ABIO', 'ABM', 'ABMD', 'ABNB', 'ABR', 'ABT', 'ABTX', 'ABUS', 'ACA', 119 | 'ACAD', 'ACB', 'ACC', 'ACCD', 'ACCO', 'ACEL', 'ACER', 'ACES', 'ACEV', 'ACGL', 'ACH', 'ACHC', 'ACI', 'ACIU', 'ACIW', 120 | 'ACLS', 'ACM', 'ACMR', 'ACN', 'ACOR', 'ACR', 'ACRE', 'ACRS', 'ACRX', 'ACTC', 'ACTG', 'ACWI', 'ACWV', 'ACWX', 'ADAP', 121 | 'ADBE', 'ADC', 'ADCT', 'ADI', 'ADM', 'ADMA', 'ADMP', 'ADMS', 'ADN', 'ADNT', 'ADP', 'ADPT', 'ADS', 'ADSK', 'ADT', 'ADTN', 122 | 'ADTX', 'ADUS', 'ADV', 'ADVM', 'AEE', 'AEG', 'AEGN', 'AEIS', 'AEL', 'AEM', 'AEO', 'AEP', 'AER', 'AERI', 'AES', 'AEZS', 123 | 'AFG', 'AFI', 'AFL', 'AFMD', 'AFRM', 'AFTY', 'AFYA', 'AG', 'AGC', 'AGCB', 'AGCO', 'AGEN', 'AGFS', 'AGG', 'AGI', 'AGIO', 124 | 'AGLE', 'AGM', 'AGNC', 'AGO', 'AGQ', 'AGR', 'AGRO', 'AGRX', 'AGS', 'AGTC', 'AGX', 'AGYS', 'AHC', 'AHCO', 'AHH', 'AHT', 125 | 'AI', 'AIA', 'AIG', 'AIMC', 'AIN', 'AINV', 'AIR', 'AIRC', 'AIRG', 'AIT', 'AIV', 'AIZ', 'AJAX', 'AJG', 'AJRD', 'AJX', 'AKAM', 126 | 'AKBA', 'AKR', 'AKRO', 'AKTS', 'AL', 'ALB', 'ALBO', 'ALC', 'ALDX', 'ALE', 'ALEC', 'ALEX', 'ALFA', 'ALG', 'ALGM', 'ALGN', 'ALGT', 127 | 'ALK', 'ALKS', 'ALL', 'ALLE', 'ALLK', 'ALLO', 'ALLT', 'ALLY', 'ALNY', 'ALPN', 'ALRM', 'ALSK', 'ALSN', 'ALT', 'ALTG', 'ALTO', 'ALTR', 128 | 'ALTU', 'ALV', 'ALVR', 'ALXN', 'ALXO', 'AM', 'AMAT', 'AMBA', 'AMBC', 'AMC', 'AMCR', 'AMCX', 'AMD', 'AME', 'AMED', 'AMG', 129 | 'AMGN', 'AMH', 'AMJ', 'AMKR', 'AMLP', 'AMN', 'AMNB', 'AMOT', 'AMP', 'AMPE', 'AMPH', 'AMPY', 'AMR', 'AMRC', 'AMRN', 'AMRS', 130 | 'AMRX', 'AMSC', 'AMSF', 'AMSWA', 'AMT', 'AMTX', 'AMWD', 'AMWL', 'AMX', 'AMZA', 'AMZN', 'AN', 'ANAB', 'ANAT', 'ANDE', 'ANET', 131 | 'ANF', 'ANGI', 'ANGL', 'ANGO', 'ANH', 'ANIK', 'ANIP', 'ANSS', 'ANTE', 'ANTM', 'AON', 'AOS', 'AOSL', 'AOUT', 'AP', 'APA', 'APAM', 132 | 'APD', 'APEI', 'APEN', 'APEX', 'APG', 'APH', 'APHA', 'API', 'APLE', 'APLS', 'APLT', 'APO', 'APOG', 'APPF', 'APPH', 'APPN', 'APPS', 133 | 'APRE', 'APRN', 'APT', 'APTO', 'APTS', 'APTV', 'APTX', 'APXT', 'APYX', 'AQB', 'AQMS', 'AQN', 'AQST', 'AQUA', 'AR', 'ARAV', 'ARAY', 134 | 'ARC', 'ARCB', 'ARCC', 'ARCH', 'ARCO', 'ARCT', 'ARD', 'ARDX', 'ARE', 'ARES', 'ARGT', 'ARGX', 'ARI', 'ARKF', 'ARKG', 'ARKK', 'ARKQ', 135 | 'ARKW', 'ARLO', 'ARLP', 'ARMK', 'ARNA', 'ARNC', 'AROC', 'AROW', 'ARQT', 'ARR', 'ARRY', 'ARVN', 'ARW', 'ARWR', 'ARYA', 'ASA', 'ASAN', 136 | 'ASB', 'ASC', 'ASGN', 'ASH', 'ASHR', 'ASHS', 'ASIX', 'ASMB', 'ASML', 'ASNAQ', 'ASND', 'ASO', 'ASPN', 'ASPS', 'ASR', 'ASRT', 'ASRV', 137 | 'ASTE', 'ASUR', 'ASYS', 'AT', 'ATAC', 'ATAX', 'ATCO', 'ATEC', 'ATEN', 'ATEX', 'ATGE', 'ATH', 'ATHM', 'ATHX', 'ATI', 'ATKR', 'ATLC', 138 | 'ATNF', 'ATNI', 'ATNM', 'ATNX', 'ATO', 'ATOM', 'ATOS', 'ATR', 'ATRA', 'ATRC', 'ATRO', 'ATRS', 'ATSG', 'ATUS', 'ATVI', 'AU', 'AUB', 139 | 'AUDC', 'AUMN', 'AUPH', 'AUTO', 'AUY', 'AVA', 'AVAV', 'AVB', 'AVCT', 'AVD', 'AVDL', 'AVEO', 'AVGO', 'AVID', 'AVIR', 'AVLR', 'AVNS', 140 | 'AVNT', 'AVRO', 'AVT', 'AVTR', 'AVXL', 'AVY', 'AVYA', 'AWAY', 'AWH', 'AWI', 'AWK', 'AWR', 'AWRE', 'AX', 'AXAS', 'AXDX', 'AXGN', 'AXL', 141 | 'AXNX', 'AXON', 'AXP', 'AXS', 'AXSM', 'AXTA', 'AXTI', 'AXU', 'AY', 'AYI', 'AYRO', 'AYX', 'AZEK', 'AZN', 'AZO', 'AZPN', 'AZUL', 'AZZ', 142 | 'B', 'BA', 'BABA', 'BAC', 'BAH', 'BAL', 'BALY', 'BAM', 'BANC', 'BAND', 'BANF', 'BANR', 'BAP', 'BATRA', 'BATRK', 'BAX', 'BB', 'BBAR', 143 | 'BBBY', 'BBCA', 'BBD', 'BBDC', 'BBEU', 'BBH', 'BBIG', 'BBIO', 'BBL', 'BBSI', 'BBU', 'BBVA', 'BBW', 'BBY', 'BC', 'BCBP', 'BCC', 'BCDA', 144 | 'BCE', 'BCEI', 'BCEL', 'BCI', 'BCLI', 'BCO', 'BCOR', 'BCOV', 'BCPC', 'BCRX', 'BCS', 'BCSF', 'BDC', 'BDN', 'BDSI', 'BDTX', 'BDX', 'BE', 145 | 'BEAM', 'BECN', 'BEEM', 'BEKE', 'BELFB', 'BEN', 'BEP', 'BEPC', 'BERY', 'BEST', 'BETZ', 'BFAM', 'BFI', 'BFLY', 'BFOR', 'BFT', 'BG', 146 | 'BGCP', 'BGFV', 'BGNE', 'BGS', 'BHC', 'BHE', 'BHF', 'BHLB', 'BHP', 'BHR', 'BHVN', 'BIB', 'BIDU', 'BIG', 'BIGC', 'BIIB', 'BIL', 'BILI', 147 | 'BILL', 'BIO', 'BIOC', 'BIP', 'BIS', 'BIV', 'BJ', 'BJK', 'BJRI', 'BK', 'BKCC', 'BKD', 'BKE', 'BKEP', 'BKF', 'BKH', 'BKI', 'BKLN', 'BKNG', 148 | 'BKR', 'BKU', 'BKYI', 'BL', 'BLCN', 'BLD', 'BLDP', 'BLDR', 'BLFS', 'BLI', 'BLK', 'BLKB', 'BLL', 'BLMN', 'BLNK', 'BLOK', 'BLU', 'BLUE', 149 | 'BLV', 'BLX', 'BMA', 'BMBL', 'BMI', 'BMO', 'BMRA', 'BMRN', 'BMTC', 'BMY', 'BND', 'BNDX', 'BNED', 'BNFT', 'BNGO', 'BNL', 'BNO', 'BNS', 150 | 'BNTX', 'BOCH', 'BOH', 'BOIL', 'BOKF', 'BOND', 'BOOM', 'BOOT', 'BOTZ', 'BOX', 'BP', 'BPFH', 'BPMC', 'BPMP', 'BPOP', 'BPT', 'BPY', 'BPYU', 151 | 'BQ', 'BR', 'BRBR', 'BRC', 'BRF', 'BRFS', 'BRG', 'BRK.B', 'BRKL', 'BRKR', 'BRKS', 'BRMK', 'BRO', 'BRP', 'BRX', 'BRY', 'BRZU', 'BSAC', 152 | 'BSBR', 'BSET', 'BSGM', 'BSIG', 'BSM', 'BSMX', 'BSQR', 'BSRR', 'BSV', 'BSX', 'BSY', 'BTAI', 'BTBT', 'BTEGF', 'BTG', 'BTI', 'BTN', 'BTNB', 153 | 'BTU', 'BTWN', 'BUD', 'BUG', 'BUR', 'BURL', 'BUSE', 'BV', 'BVN', 'BW', 'BWA', 'BWX', 'BWXT', 'BX', 'BXC', 'BXMT', 'BXP', 'BXRX', 'BXS', 154 | 'BYD', 'BYND', 'BYSI', 'BZH', 'BZQ', 'BZUN', 'C', 'CAAP', 'CAAS', 'CABA', 'CAC', 'CACC', 'CACI', 'CADE', 'CAE', 'CAF', 'CAG', 'CAH', 'CAI', 155 | 'CAJ', 'CAKE', 'CAL', 'CALA', 'CALM', 'CALX', 'CAMP', 'CAMT', 'CAN', 'CANE', 'CAPA', 'CAPL', 'CAPR', 'CAR', 'CARA', 'CARG', 'CARR', 'CARS', 156 | 'CASA', 'CASH', 'CASS', 'CASY', 'CAT', 'CATB', 'CATM', 'CATO', 'CATY', 'CB', 'CBAT', 'CBAY', 'CBB', 'CBD', 'CBIO', 'CBLAQ', 'CBOE', 'CBPO', 157 | 'CBRE', 'CBRL', 'CBSH', 'CBT', 'CBU', 'CBZ', 'CC', 'CCAC', 'CCEP', 'CCI', 'CCIV', 'CCJ', 'CCK', 'CCL', 'CCLP', 'CCMP', 'CCNE', 'CCO', 'CCOI', 158 | 'CCRN', 'CCS', 'CCX', 'CCXI', 'CD', 'CDAY', 'CDE', 'CDEV', 'CDK', 'CDLX', 'CDMO', 'CDNA', 'CDNS', 'CDR', 'CDTX', 'CDW', 'CDXC', 'CDXS', 159 | 'CDZI', 'CE', 'CECE', 'CEIX', 'CELH', 'CELJF', 'CEMB', 'CEMI', 'CENT', 'CENTA', 'CENX', 'CEQP', 'CERC', 'CERN', 'CERS', 'CERT', 'CEVA', 160 | 'CEW', 'CF', 'CFA', 'CFAC', 'CFFN', 'CFG', 'CFII', 'CFR', 'CFRX', 'CFX', 'CG', 'CGBD', 'CGC', 'CGEN', 'CGNT', 'CGNX', 'CGRO', 'CHAD', 161 | 'CHAU', 'CHCO', 'CHD', 'CHDN', 'CHE', 'CHEF', 'CHGG', 'CHH', 'CHIC', 'CHIQ', 'CHIX', 'CHK', 'CHKP', 'CHMA', 'CHNG', 'CHPT', 'CHRS', 162 | 'CHRW', 'CHS', 'CHT', 'CHTR', 'CHUY', 'CHWY', 'CHX', 'CI', 'CIA', 'CIB', 'CIBR', 'CIEN', 'CIG', 'CIIC', 'CIM', 'CINF', 'CIO', 'CIR', 163 | 'CIT', 'CIVB', 'CKH', 'CKPT', 'CL', 'CLA', 'CLAR', 'CLB', 'CLBK', 'CLBS', 'CLDR', 'CLDT', 'CLDX', 'CLF', 'CLFD', 'CLGX', 'CLH', 'CLI', 164 | 'CLII', 'CLIR', 'CLLS', 'CLMT', 'CLNC', 'CLNE', 'CLNY', 'CLOU', 'CLOV', 'CLR', 'CLS', 'CLSD', 'CLSK', 'CLSN', 'CLVR', 'CLVS', 'CLVT', 165 | 'CLW', 'CLX', 'CM', 'CMA', 'CMC', 'CMCM', 'CMCO', 'CMCSA', 'CMD', 'CME', 'CMG', 'CMI', 'CMLF', 'CMO', 'CMP', 'CMPR', 'CMPS', 'CMRE', 166 | 'CMRX', 'CMS', 'CMTL', 'CNA', 'CNC', 'CNCE', 'CNDT', 'CNET', 'CNHI', 'CNI', 'CNK', 'CNMD', 'CNNE', 'CNO', 'CNOB', 'CNP', 'CNQ', 'CNR', 167 | 'CNS', 'CNSL', 'CNST', 'CNTY', 'CNX', 'CNXC', 'CNXN', 'CNXT', 'CNYA', 'CO', 'CODI', 'CODX', 'COF', 'COG', 'COHR', 'COHU', 'COLB', 'COLD', 168 | 'COLL', 'COLM', 'COMM', 'COMS', 'CONE', 'CONN', 'COO', 'COOP', 'COP', 'COR', 'CORE', 'CORN', 'CORR', 'CORT', 'COST', 'COTY', 'COUP', 'COW', 169 | 'COWN', 'COWZ', 'CP', 'CPA', 'CPB', 'CPE', 'CPER', 'CPF', 'CPG', 'CPK', 'CPLG', 'CPLP', 'CPRI', 'CPRT', 'CPRX', 'CPS', 'CPSH', 'CPSI', 170 | 'CPSS', 'CPST', 'CPT', 'CPTA', 'CQP', 'CQQQ', 'CR', 'CRAI', 'CRBP', 'CRC', 'CRDF', 'CREE', 'CRESY', 'CRH', 'CRI', 'CRIS', 'CRK', 'CRL', 171 | 'CRM', 'CRMD', 'CRMT', 'CRNC', 'CRNT', 'CROC', 'CRON', 'CROX', 'CRS', 'CRSA', 'CRSP', 'CRSR', 'CRTO', 'CRTX', 'CRUS', 'CRVL', 'CRVS', 172 | 'CRWD', 'CRWS', 'CRY', 'CS', 'CSCO', 'CSD', 'CSGP', 'CSGS', 'CSII', 'CSIQ', 'CSL', 'CSLT', 'CSOD', 'CSPR', 'CSR', 'CSTE', 'CSTL', 'CSTM', 173 | 'CSU', 'CSV', 'CSWC', 'CSX', 'CTAS', 'CTB', 'CTBI', 'CTG', 'CTIC', 'CTLT', 'CTMX', 'CTRE', 'CTRN', 'CTS', 'CTSH', 'CTSO', 'CTT', 'CTVA', 174 | 'CTXS', 'CUB', 'CUBE', 'CUBI', 'CUE', 'CUK', 'CULP', 'CURE', 'CURI', 'CURO', 'CUTR', 'CUZ', 'CVA', 'CVAC', 'CVBF', 'CVCO', 'CVCY', 'CVE', 175 | 'CVEO', 'CVET', 'CVGI', 'CVGW', 'CVI', 'CVLG', 'CVLT', 'CVM', 'CVNA', 'CVS', 'CVX', 'CVY', 'CW', 'CWB', 'CWCO', 'CWEB', 'CWEN', 'CWH', 176 | 'CWI', 'CWK', 'CWST', 'CWT', 'CX', 'CXDC', 'CXP', 'CXW', 'CYB', 'CYBE', 'CYBR', 'CYCN', 'CYD', 'CYH', 'CYRX', 'CYTK', 'CZNC', 'CZR', 177 | 'CZZ', 'D', 'DAC', 'DADA', 'DAKT', 'DAL', 'DAN', 'DAO', 'DAR', 'DASH', 'DB', 'DBA', 'DBB', 'DBC', 'DBD', 'DBE', 'DBEF', 'DBEU', 'DBI', 178 | 'DBJP', 'DBO', 'DBP', 'DBS', 'DBV', 'DBVT', 'DBX', 'DCI', 'DCO', 'DCOM', 'DCP', 'DCPH', 'DCT', 'DD', 'DDD', 'DDG', 'DDM', 'DDOG', 179 | 'DDS', 'DE', 'DEA', 'DECK', 'DEEP', 'DEI', 'DELL', 'DEM', 'DENN', 'DEO', 'DES', 'DESP', 'DFE', 'DFEN', 'DFH', 'DFIN', 'DFJ', 'DFS', 180 | 'DG', 'DGICA', 'DGII', 'DGL', 'DGLY', 'DGNR', 'DGNS', 'DGRO', 'DGRW', 'DGS', 'DGX', 'DHC', 'DHI', 'DHR', 'DHT', 'DHX', 'DIA', 'DIG', 181 | 'DIN', 'DIOD', 'DIS', 'DISCA', 'DISCK', 'DISH', 'DJP', 'DK', 'DKL', 'DKNG', 'DKS', 'DLB', 'DLHC', 'DLN', 'DLNG', 'DLR', 'DLS', 'DLTH', 182 | 'DLTR', 'DLX', 'DM', 'DMAC', 'DMLP', 'DMRC', 'DMTK', 'DMYD', 'DNB', 'DNLI', 'DNMR', 'DNN', 'DNOW', 'DOC', 'DOCU', 'DOFSQ', 'DOG', 'DOMO', 183 | 'DON', 'DOOR', 'DORM', 'DOV', 'DOW', 'DOX', 'DOYU', 'DPST', 'DPW', 'DPZ', 'DQ', 'DRD', 'DRE', 'DRH', 'DRI', 'DRIP', 'DRIV', 'DRN', 184 | 'DRNA', 'DRQ', 'DRRX', 'DRV', 'DRVN', 'DS', 'DSKE', 'DSL', 'DSPG', 'DSX', 'DT', 'DTE', 'DTEA', 'DTEC', 'DTIL', 'DTN', 'DUG', 'DUK', 185 | 'DUSL', 'DUST', 'DVA', 'DVAX', 'DVN', 'DVY', 'DWAS', 'DWX', 'DX', 'DXC', 'DXCM', 'DXD', 'DXJ', 'DXJS', 'DXLG', 'DXPE', 'DXYN', 'DY', 186 | 'DYAI', 'DZSI', 'E', 'EA', 'EAF', 'EAR', 'EARS', 'EAT', 'EB', 'EBAY', 'EBC', 'EBF', 'EBIX', 'EBIZ', 'EBND', 'EBON', 'EBS', 'EBSB', 187 | 'EC', 'ECH', 'ECHO', 'ECL', 'ECNS', 'ECOL', 'ECOM', 'ECON', 'ECPG', 'ED', 'EDAP', 'EDC', 'EDIT', 'EDIV', 'EDOC', 'EDU', 'EDV', 'EDZ', 188 | 'EEFT', 'EEM', 'EEMV', 'EET', 'EEV', 'EEX', 'EFA', 'EFAV', 'EFC', 'EFG', 'EFSC', 'EFV', 'EFX', 'EFZ', 'EGAN', 'EGBN', 'EGHT', 'EGLE', 189 | 'EGO', 'EGOV', 'EGP', 'EGRX', 'EGY', 'EH', 'EHC', 'EHTH', 'EIDO', 'EIG', 'EIGR', 'EINC', 'EIX', 'EKSO', 'EL', 'ELAN', 'ELD', 'ELF', 190 | 'ELMD', 'ELOX', 'ELP', 'ELS', 'ELY', 'EMAN', 'EMB', 'EME', 'EMKR', 'EMLC', 'EMLP', 'EMN', 'EMQQ', 'EMR', 'EMXC', 'ENB', 'ENBL', 191 | 'ENDP', 'ENG', 'ENIA', 'ENIC', 'ENLC', 'ENLV', 'ENPH', 'ENR', 'ENS', 'ENSG', 'ENTA', 'ENTG', 'ENV', 'ENVA', 'ENZ', 'ENZL', 'EOG', 192 | 'EOLS', 'EOSE', 'EPAC', 'EPAM', 'EPAY', 'EPC', 'EPD', 'EPI', 'EPM', 'EPP', 'EPR', 'EPRT', 'EPV', 'EPZM', 'EQC', 'EQH', 'EQIX', 193 | 'EQNR', 'EQOS', 'EQR', 'EQT', 'EQX', 'ERF', 'ERIC', 'ERIE', 'ERII', 'ERJ', 'ERX', 'ERY', 'ES', 'ESCA', 'ESE', 'ESGC', 'ESGE', 194 | 'ESGU', 'ESI', 'ESNT', 'ESPO', 'ESPR', 'ESRT', 'ESS', 'ESSC', 'ESTA', 'ESTC', 'ET', 'ETH', 'ETM', 'ETN', 'ETNB', 'ETR', 'ETRN', 195 | 'ETSY', 'ETWO', 'EUFN', 'EUM', 'EUO', 'EURL', 'EURN', 'EVA', 'EVBG', 'EVC', 'EVER', 'EVFM', 'EVGN', 'EVH', 'EVLO', 'EVOK', 'EVOP', 196 | 'EVR', 'EVRG', 'EVRI', 'EVTC', 'EW', 'EWA', 'EWBC', 'EWC', 'EWD', 'EWG', 'EWH', 'EWI', 'EWJ', 'EWK', 'EWL', 'EWM', 'EWN', 'EWP', 197 | 'EWQ', 'EWS', 'EWT', 'EWU', 'EWV', 'EWW', 'EWX', 'EWY', 'EWZ', 'EXAS', 'EXC', 'EXEL', 'EXK', 'EXLS', 'EXP', 'EXPC', 'EXPD', 'EXPE', 198 | 'EXPI', 'EXPO', 'EXPR', 'EXR', 'EXTN', 'EXTR', 'EYE', 'EYEN', 'EYPT', 'EZA', 'EZJ', 'EZPW', 'EZU', 'F', 'FAF', 'FAII', 'FALN', 199 | 'FAN', 'FANG', 'FANH', 'FARO', 'FAS', 'FAST', 'FATE', 'FAZ', 'FB', 'FBC', 'FBHS', 'FBIZ', 'FBK', 'FBNC', 'FBP', 'FBT', 'FC', 'FCA', 200 | 'FCAC', 'FCBC', 'FCEL', 'FCF', 'FCFS', 'FCG', 'FCN', 'FCOM', 'FCPT', 'FCRD', 'FCX', 'FDIS', 'FDL', 'FDLO', 'FDN', 'FDP', 'FDS', 201 | 'FDUS', 'FDX', 'FE', 'FELE', 'FEM', 'FENC', 'FENG', 'FENY', 'FEP', 'FET', 'FEX', 'FEYE', 'FEZ', 'FF', 'FFBC', 'FFG', 'FFIC', 'FFIN', 202 | 'FFIV', 'FFNW', 'FFTY', 'FGD', 'FGEN', 'FHB', 'FHI', 'FHLC', 'FHN', 'FI', 'FIBK', 'FICO', 'FIDU', 'FIII', 'FINV', 'FINX', 'FIS', 203 | 'FISI', 'FISV', 'FITB', 'FIVE', 'FIVG', 'FIVN', 'FIW', 'FIX', 'FIXX', 'FIZZ', 'FL', 'FLDM', 'FLEX', 'FLGT', 'FLIC', 'FLIR', 'FLMN', 204 | 'FLNT', 'FLO', 'FLOW', 'FLR', 'FLS', 'FLT', 'FLWS', 'FLXN', 'FLY', 'FM', 'FMAT', 'FMBI', 'FMC', 'FMNB', 'FMS', 'FMX', 'FN', 'FNB', 205 | 'FNCL', 'FND', 'FNDA', 'FNDE', 'FNDF', 'FNDX', 'FNF', 'FNGS', 'FNHC', 'FNKO', 'FNLC', 'FNV', 'FOCS', 'FOE', 'FOLD', 'FOR', 'FORM', 206 | 'FORR', 'FOSL', 'FOUR', 'FOX', 'FOXA', 'FOXF', 'FPAC', 'FPE', 'FPH', 'FPI', 'FPRX', 'FPX', 'FR', 'FRAK', 'FRBK', 'FRC', 'FREE', 207 | 'FREL', 'FREQ', 'FRG', 'FRGI', 'FRHC', 'FRME', 'FRO', 'FROG', 'FRPT', 'FRSX', 'FRT', 'FRTA', 'FRX', 'FSK', 'FSKR', 'FSLR', 'FSLY', 208 | 'FSM', 'FSP', 'FSR', 'FSRV', 'FSS', 'FST', 'FSTA', 'FSTR', 'FTAG', 'FTAI', 'FTC', 'FTCH', 'FTCS', 'FTDR', 'FTEC', 'FTEK', 'FTFT', 209 | 'FTGC', 'FTI', 'FTK', 'FTNT', 'FTOC', 'FTRCQ', 'FTRI', 'FTS', 'FTV', 'FUBO', 'FUL', 'FULT', 'FUN', 'FUSE', 'FUSN', 'FUTU', 'FUTY', 210 | 'FUV', 'FV', 'FVD', 'FVRR', 'FWONA', 'FWONK', 'FWRD', 'FXA', 'FXB', 'FXC', 'FXD', 'FXE', 'FXF', 'FXG', 'FXH', 'FXI', 'FXL', 'FXN', 211 | 'FXO', 'FXP', 'FXR', 'FXU', 'FXY', 'FXZ', 'G', 'GABC', 'GAIA', 'GAIN', 'GALT', 'GAMR', 'GAN', 'GASS', 'GATX', 'GAU', 'GB', 'GBCI', 212 | 'GBDC', 'GBT', 'GBX', 'GCI', 'GCO', 'GCP', 'GD', 'GDDY', 'GDEN', 'GDOT', 'GDRX', 'GDS', 'GDX', 'GDXJ', 'GDYN', 'GE', 'GEF', 'GEL', 213 | 'GEM', 'GEN', 'GENE', 'GEO', 'GEOS', 'GERM', 'GERN', 'GES', 'GEVO', 'GFF', 'GFI', 'GFL', 'GFN', 'GGAL', 'GGB', 'GGG', 'GH', 'GHL', 214 | 'GHM', 'GHYB', 'GIB', 'GIFI', 'GIGB', 'GIII', 'GIK', 'GIL', 'GILD', 'GILT', 'GINN', 'GIS', 'GIX', 'GKOS', 'GL', 'GLAD', 'GLCN', 215 | 'GLD', 'GLDD', 'GLIN', 'GLL', 'GLMD', 'GLNG', 'GLOB', 'GLOG', 'GLOP', 'GLP', 'GLPG', 'GLPI', 'GLRE', 'GLT', 'GLUU', 'GLW', 'GLYC', 216 | 'GM', 'GMAB', 'GMBL', 'GMDA', 'GME', 'GMED', 'GMF', 'GMLP', 'GMRE', 'GMS', 'GMTX', 'GNCA', 'GNE', 'GNK', 'GNL', 'GNLN', 'GNMK', 217 | 'GNOG', 'GNOM', 'GNPX', 'GNR', 'GNRC', 'GNSS', 'GNTX', 'GNUS', 'GNW', 'GO', 'GOCO', 'GOEV', 'GOEX', 'GOGL', 'GOGO', 'GOL', 'GOLD', 218 | 'GOLF', 'GOOD', 'GOOG', 'GOOGL', 'GOOS', 'GORO', 'GOSS', 'GOVT', 'GP', 'GPC', 'GPI', 'GPK', 'GPL', 'GPMT', 'GPN', 'GPORQ', 'GPP', 219 | 'GPRE', 'GPRK', 'GPRO', 'GPS', 'GPX', 'GRA', 'GRBK', 'GRC', 'GREK', 'GRFS', 'GRMN', 'GROW', 'GRPN', 'GRTS', 'GRUB', 'GRWG', 'GS', 220 | 'GSAH', 'GSAT', 'GSBC', 'GSEW', 'GSG', 'GSHD', 'GSIE', 'GSIT', 'GSK', 'GSKY', 'GSLC', 'GSM', 'GSS', 'GSUM', 'GSX', 'GT', 'GTE', 221 | 'GTES', 'GTHX', 'GTIM', 'GTLS', 'GTN', 'GTS', 'GTT', 'GTXMQ', 'GTY', 'GUNR', 'GURU', 'GUSH', 'GVA', 'GVI', 'GVIP', 'GWB', 'GWPH', 222 | 'GWRE', 'GWW', 'GWX', 'GXC', 'GXG', 'GXGX', 'GYLD', 'H', 'HA', 'HACK', 'HAE', 'HAFC', 'HAIN', 'HAL', 'HALL', 'HALO', 'HARP', 'HAS', 223 | 'HASI', 'HAYN', 'HBAN', 'HBI', 'HBIO', 'HBM', 'HBNC', 'HBP', 'HCA', 'HCAT', 'HCC', 'HCCI', 'HCHC', 'HCI', 'HCKT', 'HCSG', 'HD', 224 | 'HDB', 'HDGE', 'HDSN', 'HDV', 'HE', 'HEAR', 'HEDJ', 'HEES', 'HEFA', 'HEI', 'HELE', 'HEP', 'HEPA', 'HERO', 'HES', 'HESM', 'HEWG', 225 | 'HEWJ', 'HEXO', 'HEZU', 'HFC', 'HFWA', 'HGEN', 'HGV', 'HHC', 'HI', 'HIBB', 'HIBS', 'HIG', 'HII', 'HIL', 'HIMS', 'HIMX', 'HIW', 226 | 'HL', 'HLF', 'HLI', 'HLIO', 'HLIT', 'HLNE', 'HLT', 'HLX', 'HMC', 'HMHC', 'HMN', 'HMST', 'HMSY', 'HMTV', 'HMY', 'HNGR', 'HNI', 227 | 'HNP', 'HOFT', 'HOG', 'HOL', 'HOLI', 'HOLX', 'HOMB', 'HOME', 'HOMZ', 'HON', 'HOOK', 'HOPE', 'HP', 'HPE', 'HPP', 'HPQ', 'HPR', 228 | 'HQY', 'HR', 'HRB', 'HRC', 'HRI', 'HRL', 'HRMY', 'HROW', 'HRTG', 'HRTX', 'HRZN', 'HSBC', 'HSC', 'HSIC', 'HSII', 'HST', 'HSTM', 229 | 'HSY', 'HT', 'HTA', 'HTBI', 'HTBK', 'HTBX', 'HTGC', 'HTGM', 'HTH', 'HTHT', 'HTLD', 'HTLF', 'HTZGQ', 'HUBB', 'HUBG', 'HUBS', 'HUGE', 230 | 'HUM', 'HUN', 'HURN', 'HUYA', 'HVT', 'HWC', 'HWCC', 'HWKN', 'HWM', 'HXL', 'HY', 'HYBB', 'HYD', 'HYFM', 'HYG', 'HYGH', 'HYLB', 231 | 'HYLD', 'HYLN', 'HYMB', 'HYMC', 'HYRE', 'HYS', 'HYXU', 'HZN', 'HZNP', 'HZO', 'IAA', 'IAC', 'IAG', 'IAI', 'IART', 'IAT', 'IAU', 232 | 'IBB', 'IBCP', 'IBIO', 'IBKR', 'IBM', 'IBN', 'IBOC', 'IBP', 'IBTX', 'IBUY', 'ICAD', 'ICE', 'ICF', 'ICFI', 'ICHR', 'ICLK', 'ICLN', 233 | 'ICLR', 'ICMB', 'ICON', 'ICPT', 'ICUI', 'ICVT', 'IDA', 'IDCC', 'IDEX', 'IDN', 'IDNA', 'IDRA', 'IDRV', 'IDT', 'IDU', 'IDV', 'IDXX', 234 | 'IDYA', 'IEA', 'IEF', 'IEFA', 'IEI', 'IEMG', 'IEO', 'IEP', 'IEUR', 'IEV', 'IEX', 'IEZ', 'IFF', 'IFGL', 'IFN', 'IFRX', 'IGC', 'IGE', 235 | 'IGF', 'IGIB', 'IGLB', 'IGM', 'IGMS', 'IGN', 'IGOV', 'IGSB', 'IGT', 'IGV', 'IHAK', 'IHDG', 'IHE', 'IHF', 'IHI', 'IHRT', 'IHY', 'IIIN', 236 | 'IIIV', 'IIN', 'IIPR', 'IIVI', 'IJH', 'IJJ', 'IJK', 'IJR', 'IJS', 'IJT', 'ILF', 'ILMN', 'ILPT', 'IMAX', 'IMGN', 'IMH', 'IMKTA', 'IMMR', 237 | 'IMO', 'IMOS', 'IMUX', 'IMV', 'IMVT', 'INCY', 'INDA', 'INDB', 'INDL', 'INDY', 'INFI', 'INFN', 'INFO', 'INFY', 'ING', 'INGN', 'INGR', 238 | 'INMD', 'INN', 'INO', 'INOD', 'INOV', 'INSG', 'INSM', 'INSP', 'INSW', 'INT', 'INTC', 'INTEQ', 'INTF', 'INTU', 'INVA', 'INVE', 'INVH', 239 | 'IO', 'IONS', 'IOO', 'IOSP', 'IOVA', 'IP', 'IPAR', 'IPAY', 'IPFF', 'IPG', 'IPGP', 'IPHI', 'IPI', 'IPO', 'IPOD', 'IPOE', 'IPOF', 'IPV', 240 | 'IQ', 'IQDF', 'IQLT', 'IQV', 'IR', 'IRBO', 'IRBT', 'IRDM', 'IRM', 'IRT', 'IRTC', 'IRWD', 'ISBC', 'ISEE', 'ISIG', 'ISRA', 'ISRG', 'IT', 241 | 'ITA', 'ITB', 'ITCI', 'ITEQ', 'ITGR', 'ITI', 'ITM', 'ITOT', 'ITP', 'ITRI', 'ITRN', 'ITT', 'ITUB', 'ITW', 'IUSB', 'IUSG', 'IUSV', 'IVAC', 242 | 'IVC', 'IVE', 'IVLU', 'IVOL', 'IVR', 'IVV', 'IVW', 'IVZ', 'IWB', 'IWC', 'IWD', 'IWF', 'IWM', 'IWN', 'IWO', 'IWP', 'IWR', 'IWS', 'IWV', 243 | 'IXC', 'IXJ', 'IXN', 'IXP', 'IXUS', 'IYE', 'IYF', 'IYG', 'IYH', 'IYJ', 'IYM', 'IYR', 'IYT', 'IYW', 'IYZ', 'IZEA', 'J', 'JACK', 'JAGX', 244 | 'JAMF', 'JAX', 'JAZZ', 'JBGS', 'JBHT', 'JBL', 'JBLU', 'JBSS', 'JBT', 'JCI', 'JCOM', 'JD', 'JDST', 'JE', 'JEF', 'JELD', 'JETS', 'JG', 245 | 'JHG', 'JIH', 'JILL', 'JJC', 'JJG', 'JJSF', 'JKHY', 'JKS', 'JLL', 'JMIA', 'JNCE', 'JNJ', 'JNK', 'JNPR', 'JNUG', 'JO', 'JOBS', 'JOE', 246 | 'JOET', 'JP', 'JPEM', 'JPIN', 'JPM', 'JPUS', 'JRVR', 'JUST', 'JWN', 'JWS', 'JYNT', 'K', 'KAI', 'KALA', 'KALU', 'KALV', 'KAMN', 'KAR', 247 | 'KARS', 'KB', 'KBA', 'KBAL', 'KBE', 'KBH', 'KBR', 'KBWB', 'KC', 'KCE', 'KDMN', 'KDNY', 'KDP', 'KE', 'KELYA', 'KEP', 'KERN', 'KEX', 'KEY', 248 | 'KEYS', 'KFRC', 'KFY', 'KGC', 'KHC', 'KIDS', 'KIE', 'KIM', 'KIN', 'KIRK', 'KKR', 'KL', 'KLAC', 'KLDO', 'KLIC', 'KLR', 'KMB', 'KMDA', 249 | 'KMI', 'KMPH', 'KMPR', 'KMT', 'KMX', 'KN', 'KNDI', 'KNL', 'KNOP', 'KNSA', 'KNSL', 'KNX', 'KO', 'KOD', 'KODK', 'KOF', 'KOLD', 'KOP', 250 | 'KOPN', 'KORU', 'KOS', 'KPTI', 'KR', 'KRA', 'KRC', 'KRE', 'KREF', 'KRG', 'KRMD', 'KRNT', 'KRNY', 'KRO', 'KRON', 'KRP', 'KRTX', 'KRYS', 251 | 'KSA', 'KSS', 'KSU', 'KT', 'KTB', 'KTCC', 'KTOS', 'KURA', 'KVHI', 'KW', 'KWEB', 'KWR', 'KXIN', 'KYN', 'KZIA', 'KZR', 'L', 'LABD', 252 | 'LABU', 'LAC', 'LAD', 'LADR', 'LAKE', 'LAMR', 'LANC', 'LAND', 'LASR', 'LAUR', 'LAZ', 'LAZR', 'LB', 'LBAI', 'LBJ', 'LBRDA', 'LBRDK', 253 | 'LBRT', 'LBTYA', 'LBTYK', 'LC', 'LCI', 'LCII', 'LCNB', 'LCTX', 'LCUT', 'LDEM', 'LDL', 'LDOS', 'LE', 'LEA', 'LEAF', 'LECO', 'LEE', 254 | 'LEG', 'LEGH', 'LEGN', 'LEJU', 'LEMB', 'LEN', 'LESL', 'LEU', 'LEVI', 'LFC', 'LFMD', 'LFT', 'LFUS', 'LFVN', 'LGIH', 'LGND', 'LH', 255 | 'LHCG', 'LHX', 'LI', 'LII', 'LILA', 'LILAK', 'LIN', 'LINC', 'LIND', 'LIT', 'LITE', 'LIVN', 'LIVX', 'LJPC', 'LKFN', 'LKNCY', 'LKQ', 256 | 'LL', 'LLNW', 'LLY', 'LMAT', 'LMND', 'LMNR', 'LMNX', 'LMRK', 'LMT', 'LNC', 'LNDC', 'LNG', 'LNN', 'LNT', 'LNTH', 'LOB', 'LOCO', 'LODE', 257 | 'LOGI', 'LOMA', 'LOOP', 'LOPE', 'LORL', 'LOTZ', 'LOUP', 'LOV', 'LOVE', 'LOW', 'LPCN', 'LPG', 'LPI', 'LPL', 'LPLA', 'LPRO', 'LPSN', 258 | 'LPX', 'LQD', 'LQDA', 'LQDH', 'LQDT', 'LRCX', 'LRGF', 'LRN', 'LSCC', 'LSI', 'LSPD', 'LSTR', 'LSXMA', 'LSXMK', 'LTC', 'LTHM', 'LTPZ', 259 | 'LTRPA', 'LU', 'LULU', 'LUMN', 'LUNG', 'LUV', 'LVS', 'LW', 'LX', 'LXFR', 'LXP', 'LXRX', 'LXU', 'LYB', 'LYFT', 'LYG', 'LYTS', 'LYV', 260 | 'LZB', 'M', 'MA', 'MAA', 'MAC', 'MACK', 'MAG', 'MAGA', 'MAGS', 'MAIN', 'MAN', 'MANH', 'MANT', 'MANU', 'MAR', 'MARA', 'MARK', 'MAS', 261 | 'MASI', 'MAT', 'MATW', 'MATX', 'MAXN', 'MAXR', 'MBB', 'MBI', 'MBIO', 'MBT', 'MBUU', 'MBWM', 'MC', 'MCBC', 'MCD', 'MCF', 'MCFE', 'MCFT', 262 | 'MCHI', 'MCHP', 'MCK', 'MCO', 'MCRB', 'MCRI', 'MCS', 'MCY', 'MD', 'MDB', 'MDC', 'MDCA', 'MDGL', 'MDIV', 'MDLA', 'MDLZ', 'MDP', 'MDRX', 263 | 'MDT', 'MDU', 'MDXG', 'MDY', 'MDYG', 'MED', 'MEDP', 'MEG', 'MEI', 'MEIP', 'MELI', 'MEOH', 'MERC', 'MESA', 'MESO', 'MET', 'MEXX', 'MFA', 264 | 'MFC', 'MFG', 'MFGP', 'MFIN', 'MG', 'MGA', 'MGC', 'MGEE', 'MGI', 'MGIC', 'MGK', 'MGLN', 'MGM', 'MGNI', 'MGNX', 'MGP', 'MGPI', 'MGRC', 265 | 'MGTA', 'MGTX', 'MGV', 'MGY', 'MHK', 'MHLD', 'MHO', 'MIC', 'MIDD', 'MIDU', 'MIK', 'MILE', 'MIME', 'MIND', 'MIST', 'MITK', 'MITT', 'MIXT', 266 | 'MJ', 'MKC', 'MKL', 'MKSI', 'MKTX', 'MLCO', 'MLHR', 'MLI', 'MLM', 'MLND', 'MLPA', 'MLPX', 'MLR', 'MMC', 'MMI', 'MMLP', 'MMM', 'MMP', 267 | 'MMS', 'MMSI', 'MMYT', 'MN', 'MNKD', 'MNKKQ', 'MNOV', 'MNR', 'MNRL', 'MNRO', 'MNSO', 'MNST', 'MNTX', 'MO', 'MOAT', 'MOD', 'MODN', 'MODV', 268 | 'MOGO', 'MOH', 'MOMO', 'MOO', 'MORN', 'MOS', 'MOV', 'MP', 'MPAA', 'MPC', 'MPLN', 'MPLX', 'MPW', 'MPWR', 'MPX', 'MRC', 'MRCC', 'MRCY', 269 | 'MREO', 'MRK', 'MRKR', 'MRLN', 'MRNA', 'MRNS', 'MRO', 'MRSN', 'MRTN', 'MRTX', 'MRVI', 'MRVL', 'MS', 'MSA', 'MSB', 'MSCI', 'MSEX', 'MSFT', 270 | 'MSGE', 'MSGN', 'MSGS', 'MSI', 'MSM', 'MSON', 'MSOS', 'MSP', 'MSTR', 'MT', 'MTA', 'MTB', 'MTCH', 'MTD', 'MTDR', 'MTEM', 'MTG', 'MTH', 'MTL', 271 | 'MTLS', 'MTN', 'MTOR', 'MTRN', 'MTRX', 'MTSC', 'MTSI', 'MTUM', 'MTW', 'MTX', 'MTZ', 'MU', 'MUB', 'MUFG', 'MUNI', 'MUR', 'MUSA', 'MUX', 272 | 'MVIS', 'MVO', 'MWA', 'MWK', 'MX', 'MXI', 'MXIM', 'MXL', 'MYE', 'MYGN', 'MYOV', 'MYRG', 'MYY', 'MZZ', 'NAIL', 'NAK', 'NANR', 'NARI', 273 | 'NAT', 'NATI', 'NAV', 'NAVB', 'NAVI', 'NBEV', 'NBHC', 'NBIX', 'NBLX', 'NBR', 'NBRV', 'NBSE', 'NBTB', 'NCLH', 'NCMI', 'NCNO', 'NCR', 274 | 'NCTY', 'NDAQ', 'NDLS', 'NDSN', 'NEE', 'NEM', 'NEO', 'NEOG', 'NEOS', 'NEP', 'NEPT', 'NERD', 'NERV', 'NESR', 'NET', 'NETL', 'NEU', 'NEW', 275 | 'NEWR', 'NEWT', 'NEX', 'NFBK', 'NFE', 'NFG', 'NFLX', 'NG', 'NGA', 'NGAC', 'NGD', 'NGG', 'NGL', 'NGM', 'NGS', 'NGVC', 'NGVT', 'NH', 276 | 'NHC', 'NHI', 'NHTC', 'NI', 'NIB', 'NICE', 'NINE', 'NIO', 'NIU', 'NJR', 'NK', 'NKE', 'NKLA', 'NKTR', 'NKTX', 'NL', 'NLOK', 'NLS', 'NLSN', 277 | 'NLTX', 'NLY', 'NM', 'NMCI', 'NMFC', 'NMIH', 'NMM', 'NMR', 'NMRD', 'NMRK', 'NMTR', 'NNA', 'NNBR', 'NNDM', 'NNI', 'NNN', 'NNOX', 'NNVC', 278 | 'NOA', 'NOAH', 'NOBL', 'NOC', 'NOG', 'NOK', 'NOMD', 'NOV', 'NOVA', 'NOVT', 'NOW', 'NP', 'NPA', 'NPO', 'NPTN', 'NR', 'NRBO', 'NRG', 'NRP', 279 | 'NRT', 'NRZ', 'NS', 'NSA', 'NSC', 'NSCO', 'NSIT', 'NSP', 'NSSC', 'NSTG', 'NTAP', 'NTCO', 'NTCT', 'NTEC', 'NTES', 'NTGR', 'NTLA', 'NTNX', 280 | 'NTP', 'NTR', 'NTRA', 'NTRS', 'NTUS', 'NTWK', 'NUAN', 'NUE', 'NUGT', 'NUS', 'NUVA', 'NVAX', 'NVCR', 'NVDA', 'NVEE', 'NVGS', 'NVMI', 'NVO', 281 | 'NVRO', 'NVS', 'NVST', 'NVT', 'NVTA', 'NWBI', 'NWE', 'NWG', 'NWL', 'NWN', 'NWPX', 'NWS', 'NWSA', 'NX', 'NXE', 'NXGN', 'NXPI', 'NXRT', 'NXST', 282 | 'NXTC', 'NXTD', 'NYCB', 'NYMT', 'NYMX', 'NYT', 'O', 'OAS', 'OBSV', 'OC', 'OCDX', 'OCFC', 'OCFT', 'OCGN', 'OCN', 'OCSI', 'OCSL', 'OCUL', 'OCX', 283 | 'ODFL', 'ODP', 'ODT', 'OEC', 'OEF', 'OEG', 'OESX', 'OFC', 'OFG', 'OFIX', 'OGE', 'OGI', 'OGIG', 'OGS', 'OHI', 'OI', 'OIH', 'OII', 'OIS', 284 | 'OKE', 'OKTA', 'OLED', 'OLLI', 'OLN', 'OLP', 'OMC', 'OMCL', 'OMER', 'OMEX', 'OMF', 'OMI', 'OMP', 'ON', 'ONB', 'ONCS', 'ONCT', 'ONEM', 285 | 'ONLN', 'ONTO', 'OOMA', 'OPCH', 'OPEN', 'OPI', 'OPK', 'OPRA', 'OPRX', 'OPTT', 'OPY', 'OR', 'ORA', 'ORAN', 'ORBC', 'ORC', 'ORCC', 'ORCL', 286 | 'ORGO', 'ORI', 'ORIC', 'ORLY', 'ORMP', 'ORN', 'ORTX', 'OSBC', 'OSG', 'OSH', 'OSIS', 'OSK', 'OSPN', 'OSTK', 'OSUR', 'OSW', 'OTEX', 'OTIC', 287 | 'OTIS', 'OTRK', 'OTTR', 'OUNZ', 'OUSA', 'OUT', 'OVID', 'OVLH', 'OVT', 'OVV', 'OXFD', 'OXM', 'OXSQ', 'OXY', 'OZK', 'OZON', 'PAA', 'PAAS', 288 | 'PACB', 'PACE', 'PACK', 'PACW', 'PAE', 'PAG', 'PAGP', 'PAGS', 'PAHC', 'PAM', 'PANW', 'PAR', 'PARR', 'PASG', 'PATK', 'PAVE', 'PAVM', 'PAX', 289 | 'PAYA', 'PAYC', 'PAYS', 'PAYX', 'PB', 'PBA', 'PBCT', 'PBF', 'PBFX', 'PBH', 'PBI', 'PBPB', 'PBR', 'PBT', 'PBW', 'PBYI', 'PCAR', 'PCEF', 290 | 'PCG', 'PCH', 'PCOM', 'PCRX', 'PCSB', 'PCTI', 'PCTY', 'PCY', 'PCYG', 'PCYO', 'PD', 'PDAC', 'PDBC', 'PDCE', 'PDCO', 'PDD', 'PDFS', 'PDM', 291 | 'PDP', 'PDS', 'PEAK', 'PEB', 'PEBO', 'PEG', 'PEGA', 'PEI', 'PEJ', 'PEN', 'PENN', 'PEO', 'PEP', 'PERI', 'PERS', 'PESI', 'PETQ', 'PETS', 292 | 'PEY', 'PEZ', 'PFBC', 'PFC', 'PFE', 'PFF', 'PFFA', 'PFG', 'PFGC', 'PFLT', 'PFM', 'PFMT', 'PFPT', 'PFS', 'PFSI', 'PFSW', 'PFX', 'PG', 'PGC', 293 | 'PGEN', 'PGF', 'PGJ', 'PGNY', 'PGR', 'PGRE', 'PGTI', 'PGX', 'PH', 'PHAS', 'PHAT', 'PHB', 'PHG', 'PHIO', 'PHM', 'PHO', 'PHR', 'PHX', 'PI', 294 | 'PICK', 'PICO', 'PID', 'PIE', 'PII', 'PIN', 'PINC', 'PING', 'PINS', 'PIPR', 'PIRS', 'PIXY', 'PIZ', 'PJP', 'PJT', 'PK', 'PKE', 'PKG', 'PKI', 295 | 'PKOH', 'PKW', 'PKX', 'PLAB', 'PLAN', 'PLAY', 'PLBY', 'PLCE', 'PLD', 'PLG', 'PLL', 'PLMR', 'PLNT', 'PLOW', 'PLSE', 'PLT', 'PLTK', 'PLTR', 'PLUG', 296 | 'PLUS', 'PLX', 'PLXS', 'PLYA', 'PM', 'PMT', 'PNC', 'PNFP', 'PNM', 'PNNT', 'PNQI', 'PNR', 'PNTG', 'PNW', 'PODD', 'POOL', 'POR', 'POST', 'POTX', 297 | 'POWI', 'POWW', 'PPA', 'PPBI', 'PPBT', 'PPC', 'PPD', 'PPG', 'PPH', 'PPL', 'PQG', 'PRA', 'PRAA', 'PRAH', 'PRAX', 'PRCH', 'PRDO', 'PRF', 'PRFT', 298 | 'PRFZ', 'PRG', 'PRGO', 'PRGS', 'PRI', 'PRIM', 'PRK', 'PRLB', 'PRMW', 'PRN', 'PRO', 'PROF', 'PROG', 'PRPB', 'PRPH', 'PRPL', 'PRQR', 'PRSP', 299 | 'PRTA', 'PRTK', 'PRTS', 'PRTY', 'PRU', 'PRVB', 'PS', 'PSA', 'PSAC', 'PSB', 'PSCH', 'PSEC', 'PSEP', 'PSL', 'PSMT', 'PSN', 'PSNL', 'PSO', 'PSP', 300 | 'PSQ', 'PST', 'PSTG', 'PSTH', 'PSTI', 'PSTX', 'PSX', 'PSXP', 'PTC', 'PTCT', 'PTE', 'PTEN', 'PTF', 'PTGX', 'PTH', 'PTLC', 'PTMN', 'PTNQ', 'PTON', 301 | 'PTPI', 'PTR', 'PTVCB', 'PTVE', 'PUK', 'PUMP', 'PVAC', 'PVG', 'PVH', 'PVL', 'PWFL', 'PWR', 'PXD', 'PXH', 'PXI', 'PXJ', 'PXLW', 'PYPL', 'PZA', 302 | 'PZN', 'PZZA', 'QABA', 'QADA', 'QCLN', 'QCOM', 'QCRH', 'QD', 'QDEL', 'QELL', 'QEP', 'QFIN', 'QGEN', 'QID', 'QIWI', 'QLD', 'QLGN', 'QLYS', 'QMCO', 303 | 'QNST', 'QQEW', 'QQQ', 'QQQE', 'QQQJ', 'QQQM', 'QRTEA', 'QRVO', 'QS', 'QSR', 'QTEC', 'QTNT', 'QTRX', 'QTS', 'QTT', 'QTWO', 'QUAD', 'QUAL', 'QUIK', 304 | 'QUMU', 'QUOT', 'QURE', 'QYLD', 'R', 'RACE', 'RAD', 'RADA', 'RAIL', 'RAMP', 'RAPT', 'RARE', 'RAVE', 'RAVN', 'RBA', 'RBAC', 'RBBN', 'RBC', 'RBCAA', 305 | 'RC', 'RCEL', 'RCI', 'RCII', 'RCKT', 'RCL', 'RCM', 'RCMT', 'RCUS', 'RDFN', 'RDHL', 'RDI', 'RDN', 'RDNT', 'RDS.A', 'RDS.B', 'RDUS', 'RDWR', 'RDY', 306 | 'RE', 'REAL', 'REDU', 'REED', 'REET', 'REFR', 'REG', 'REGI', 'REGL', 'REGN', 'REI', 'REK', 'REKR', 'RELL', 'REM', 'REMX', 'RENN', 'REPH', 'REPL', 307 | 'RES', 'RESN', 'RETA', 'RETL', 'REV', 'REVG', 'REW', 'REXR', 'REYN', 'REZ', 'REZI', 'RF', 'RFIL', 'RFL', 'RFP', 'RGA', 'RGEN', 'RGLD', 'RGLS', 308 | 'RGNX', 'RGP', 'RGR', 'RGS', 'RH', 'RHI', 'RHP', 'RICK', 'RIDE', 'RIG', 'RIGL', 'RILY', 'RING', 'RIOT', 'RJA', 'RJF', 'RJI', 'RJN', 'RKDA', 'RKT', 309 | 'RL', 'RLAY', 'RLGT', 'RLGY', 'RLH', 'RLI', 'RLJ', 'RLMD', 'RLX', 'RM', 'RMAX', 'RMBS', 'RMD', 'RMNI', 'RMO', 'RMTI', 'RNET', 'RNG', 'RNLX', 'RNR', 310 | 'RNST', 'RNWK', 'ROAD', 'ROBO', 'ROCK', 'RODM', 'ROG', 'ROIC', 'ROK', 'ROKU', 'ROL', 'ROLL', 'ROM', 'ROOT', 'ROP', 'ROST', 'RP', 'RPAI', 'RPAR', 311 | 'RPAY', 'RPD', 'RPG', 'RPLA', 'RPM', 'RPRX', 'RPT', 'RPV', 'RRC', 'RRD', 'RRGB', 'RRR', 'RS', 'RSG', 'RSI', 'RSP', 'RSX', 'RTH', 'RTLR', 'RTP', 312 | 'RTX', 'RUBY', 'RUN', 'RUSHA', 'RUSL', 'RUTH', 'RVLV', 'RVMD', 'RVNC', 'RVP', 'RVSB', 'RWJ', 'RWK', 'RWL', 'RWLK', 'RWM', 'RWO', 'RWR', 'RWT', 313 | 'RWX', 'RXL', 'RXN', 'RXT', 'RY', 'RYAAY', 'RYAM', 'RYB', 'RYH', 'RYI', 'RYN', 'RYTM', 'SA', 'SAA', 'SABR', 'SAFE', 'SAFM', 'SAFT', 'SAGE', 'SAH', 314 | 'SAIA', 'SAIC', 'SAII', 'SAIL', 'SAM', 'SAN', 'SAND', 'SANM', 'SANW', 'SAP', 'SASR', 'SATS', 'SAVA', 'SAVE', 'SB', 'SBAC', 'SBBP', 'SBCF', 'SBGI', 315 | 'SBH', 'SBIO', 'SBLK', 'SBNY', 'SBRA', 'SBS', 'SBSI', 'SBSW', 'SBUX', 'SC', 'SCCO', 'SCHA', 'SCHB', 'SCHC', 'SCHD', 'SCHE', 'SCHF', 'SCHG', 'SCHH', 316 | 'SCHL', 'SCHM', 'SCHN', 'SCHP', 'SCHR', 'SCHV', 'SCHW', 'SCHX', 'SCHZ', 'SCI', 'SCJ', 'SCL', 'SCM', 'SCO', 'SCOR', 'SCPL', 'SCS', 'SCSC', 'SCU', 317 | 'SCVL', 'SCWX', 'SCYX', 'SCZ', 'SD', 'SDC', 'SDGR', 'SDIV', 'SDOW', 'SDS', 'SDY', 'SE', 'SEAC', 'SEAS', 'SECO', 'SECT', 'SEDG', 'SEE', 'SEEL', 318 | 'SEER', 'SEF', 'SEIC', 'SELB', 'SEM', 'SENS', 'SESN', 'SF', 'SFBS', 'SFE', 'SFIX', 'SFL', 'SFM', 'SFNC', 'SFT', 'SGC', 'SGEN', 'SGFY', 'SGG', 319 | 'SGH', 'SGLB', 'SGMO', 'SGMS', 'SGOL', 'SGRY', 'SGU', 'SH', 'SHAK', 'SHEN', 'SHLS', 'SHLX', 'SHO', 'SHOO', 'SHOP', 'SHW', 'SHY', 'SHYF', 'SHYG', 320 | 'SI', 'SIBN', 'SID', 'SIEB', 'SIEN', 'SIFY', 'SIG', 'SIGA', 'SIGI', 'SII', 'SIL', 'SILJ', 'SILK', 'SILV', 'SIMO', 'SINA', 'SINO', 'SIOX', 'SIRI', 321 | 'SITC', 'SITE', 'SIVB', 'SIVR', 'SIX', 'SIZE', 'SJB', 'SJI', 'SJM', 'SJNK', 'SJR', 'SJT', 'SJW', 'SKF', 'SKLZ', 'SKM', 'SKT', 'SKX', 'SKY', 'SKYW', 322 | 'SKYY', 'SLAB', 'SLB', 'SLCA', 'SLDB', 'SLF', 'SLG', 'SLGN', 'SLM', 'SLNO', 'SLP', 'SLQT', 'SLRC', 'SLS', 'SLV', 'SLX', 'SLYV', 'SM', 'SMAR', 323 | 'SMBK', 'SMCI', 'SMDV', 'SMED', 'SMFG', 'SMG', 'SMH', 'SMHI', 'SMLP', 'SMMT', 'SMN', 'SMOG', 'SMP', 'SMPL', 'SMSI', 'SMTC', 'SMTX', 'SNA', 'SNAP', 324 | 'SNBR', 'SNCR', 'SND', 'SNDL', 'SNDR', 'SNDX', 'SNE', 'SNEX', 'SNLN', 'SNN', 'SNOW', 'SNP', 'SNPR', 'SNPS', 'SNR', 'SNV', 'SNX', 'SNY', 'SO', 325 | 'SOAC', 'SOCL', 'SOGO', 'SOHU', 'SOI', 'SOL', 'SOLO', 'SON', 'SONO', 'SOS', 'SOXL', 'SOXS', 'SOXX', 'SOYB', 'SP', 'SPAB', 'SPAK', 'SPB', 'SPCE', 326 | 'SPCX', 'SPDN', 'SPDW', 'SPEM', 'SPEU', 'SPG', 'SPGI', 'SPH', 'SPHB', 'SPHD', 'SPHQ', 'SPI', 'SPIB', 'SPIP', 'SPKE', 'SPLB', 'SPLG', 'SPLK', 327 | 'SPLV', 'SPNE', 'SPNS', 'SPNT', 'SPOK', 'SPOT', 'SPPI', 'SPR', 'SPRO', 'SPRQ', 'SPRT', 'SPSB', 'SPSC', 'SPSM', 'SPT', 'SPTI', 'SPTL', 'SPTM', 328 | 'SPTN', 'SPTS', 'SPWH', 'SPWR', 'SPXC', 'SPXL', 'SPXS', 'SPXU', 'SPXZ', 'SPY', 'SPYD', 'SPYG', 'SPYV', 'SQ', 'SQBG', 'SQM', 'SQQQ', 'SR', 'SRAC', 329 | 'SRAX', 'SRC', 'SRCE', 'SRCL', 'SRDX', 'SRE', 'SRET', 'SREV', 'SRG', 'SRGA', 'SRI', 'SRLN', 'SRLP', 'SRNE', 'SRPT', 'SRRK', 'SRS', 'SRT', 'SRTY', 330 | 'SRVR', 'SSB', 'SSD', 'SSL', 'SSNC', 'SSO', 'SSP', 'SSPK', 'SSRM', 'SSSS', 'SSTK', 'SSYS', 'ST', 'STAA', 'STAG', 'STAR', 'STAY', 'STBA', 'STC', 331 | 'STCN', 'STE', 'STEP', 'STFC', 'STIC', 'STIM', 'STKL', 'STL', 'STLA', 'STLD', 'STM', 'STMP', 'STNE', 'STNG', 'STOK', 'STON', 'STOR', 'STPK', 332 | 'STRA', 'STRL', 'STRO', 'STT', 'STWD', 'STX', 'STXS', 'STZ', 'SU', 'SUBZ', 'SUI', 'SUM', 'SUMO', 'SUN', 'SUNS', 'SUNW', 'SUP', 'SUPN', 'SUPV', 333 | 'SURF', 'SUSL', 'SVAC', 'SVC', 'SVM', 'SVMK', 'SVRA', 'SVVC', 'SVXY', 'SWAV', 'SWBI', 'SWCH', 'SWI', 'SWIR', 'SWK', 'SWKS', 'SWM', 'SWN', 'SWX', 334 | 'SXC', 'SXI', 'SXT', 'SYBX', 'SYF', 'SYK', 'SYKE', 'SYNA', 'SYNC', 'SYNH', 'SYNL', 'SYRS', 'SYX', 'SYY', 'T', 'TA', 'TACO', 'TACT', 'TAIL', 'TAK', 335 | 'TAL', 'TALO', 'TAN', 'TAP', 'TARO', 'TAST', 'TBA', 'TBBK', 'TBF', 'TBI', 'TBIO', 'TBK', 'TBNK', 'TBPH', 'TBT', 'TCBI', 'TCBK', 'TCDA', 'TCF', 336 | 'TCMD', 'TCOM', 'TCON', 'TCPC', 'TCRR', 'TCS', 'TCX', 'TD', 'TDC', 'TDG', 'TDIV', 'TDOC', 'TDS', 'TDW', 'TDY', 'TEAM', 'TECH', 'TECK', 'TECL', 337 | 'TECS', 'TEF', 'TEL', 'TELL', 'TEN', 'TENB', 'TEO', 'TER', 'TEUM', 'TEVA', 'TEX', 'TFC', 'TFFP', 'TFI', 'TFLO', 'TFSL', 'TFX', 'TG', 'TGB', 'TGH', 338 | 'TGI', 'TGNA', 'TGP', 'TGS', 'TGT', 'TGTX', 'THBR', 'THC', 'THCA', 'THCB', 'THCX', 'THD', 'THFF', 'THG', 'THO', 'THR', 'THRM', 'THS', 'TIGR', 339 | 'TILE', 'TIMB', 'TIP', 'TISI', 'TITN', 'TJX', 'TK', 'TKC', 'TKR', 'TLH', 'TLMD', 'TLND', 'TLRY', 'TLS', 'TLSA', 'TLT', 'TLYS', 'TM', 'TMDX', 340 | 'TME', 'TMF', 'TMHC', 'TMO', 'TMP', 'TMQ', 'TMST', 'TMUS', 'TMV', 'TMX', 'TNA', 'TNC', 'TNDM', 'TNET', 'TNK', 'TNL', 'TNP', 'TOL', 'TOT', 'TOUR', 341 | 'TOWN', 'TPB', 'TPC', 'TPCO', 'TPGY', 'TPH', 'TPIC', 'TPOR', 'TPR', 'TPTX', 'TPVG', 'TPX', 'TQQQ', 'TR', 'TRC', 'TREC', 'TREE', 'TREX', 'TRGP', 342 | 'TRHC', 'TRI', 'TRIB', 'TRIL', 'TRIP', 'TRIT', 'TRMB', 'TRMK', 'TRN', 'TRNO', 'TROW', 'TROX', 'TRP', 'TRQ', 'TRS', 'TRST', 'TRTN', 'TRTX', 'TRU', 343 | 'TRUE', 'TRUP', 'TRV', 'TRVG', 'TRVN', 'TRX', 'TS', 'TSCO', 'TSE', 'TSEM', 'TSLA', 'TSLX', 'TSM', 'TSN', 'TSQ', 'TT', 'TTAC', 'TTC', 'TTCF', 'TTD', 344 | 'TTEC', 'TTEK', 'TTGT', 'TTI', 'TTM', 'TTMI', 'TTNP', 'TTOO', 'TTT', 'TTWO', 'TU', 'TUFN', 'TUP', 'TUR', 'TURN', 'TUSK', 'TV', 'TVTX', 'TVTY', 345 | 'TW', 'TWI', 'TWIN', 'TWLO', 'TWM', 'TWNK', 'TWO', 'TWOU', 'TWST', 'TWTR', 'TX', 'TXG', 'TXMD', 'TXN', 'TXRH', 'TXT', 'TYD', 'TYL', 'TYME', 'TYO', 346 | 'TZA', 'TZOO', 'U', 'UA', 'UAA', 'UAL', 'UAMY', 'UAN', 'UAVS', 'UBA', 'UBER', 'UBS', 'UBSI', 'UBT', 'UBX', 'UCBI', 'UCO', 'UCTT', 'UDN', 'UDOW', 347 | 'UDR', 'UE', 'UEC', 'UEIC', 'UEPS', 'UFCS', 'UFI', 'UFO', 'UFPI', 'UFS', 'UGA', 'UGI', 'UGL', 'UGP', 'UHAL', 'UHS', 'UHT', 'UI', 'UIHC', 'UIS', 348 | 'UL', 'ULBI', 'ULE', 'ULTA', 'UMBF', 'UMC', 'UMDD', 'UMH', 'UMPQ', 'UNF', 'UNFI', 'UNG', 'UNH', 'UNIT', 'UNL', 'UNM', 'UNP', 'UNVR', 'UPLD', 349 | 'UPRO', 'UPS', 'UPST', 'UPWK', 'URA', 'URBN', 'URE', 'URGN', 'URI', 'URNM', 'URTH', 'URTY', 'USAC', 'USAK', 'USAT', 'USB', 'USCR', 'USD', 'USDU', 350 | 'USFD', 'USHY', 'USIG', 'USL', 'USM', 'USMC', 'USMV', 'USNA', 'USO', 'USPH', 'UST', 'USX', 'UTHR', 'UTI', 'UTL', 'UTSI', 'UTSL', 'UTZ', 'UUP', 351 | 'UUUU', 'UVE', 'UVSP', 'UVV', 'UVXY', 'UWM', 'UWMC', 'UXIN', 'UYG', 'UYM', 'V', 'VAC', 'VALE', 'VALPQ', 'VAPO', 'VAR', 'VAW', 'VB', 'VBIV', 'VBK', 352 | 'VBLT', 'VBR', 'VBTX', 'VC', 'VCEL', 'VCIT', 'VCLT', 'VCNX', 'VCR', 'VCRA', 'VCSH', 'VCTR', 'VCVC', 'VCYT', 'VDC', 'VDE', 'VEA', 'VEC', 'VECO', 353 | 'VEDL', 'VEEV', 'VEON', 'VER', 'VERI', 'VERU', 'VET', 'VEU', 'VFC', 'VFF', 'VFH', 'VG', 'VGAC', 'VGIT', 'VGK', 'VGLT', 'VGR', 'VGSH', 'VGT', 'VGZ', 354 | 'VHC', 'VHT', 'VIAC', 'VIACA', 'VIAV', 'VICI', 'VICR', 'VIE', 'VIG', 'VIH', 'VIPS', 'VIR', 'VIRT', 'VIRX', 'VIS', 'VISL', 'VITL', 'VIV', 'VIVO', 355 | 'VIXM', 'VIXY', 'VKTX', 'VLDR', 'VLO', 'VLRS', 'VLUE', 'VLY', 'VMBS', 'VMC', 'VMI', 'VMW', 'VNDA', 'VNE', 'VNET', 'VNO', 'VNOM', 'VNQ', 'VNQI', 356 | 'VNRX', 'VNT', 'VNTR', 'VO', 'VOC', 'VOD', 'VOE', 'VOLT', 'VONV', 'VOO', 'VOOG', 'VOT', 'VOX', 'VOXX', 'VOYA', 'VPG', 'VPL', 'VPU', 'VRA', 'VRAY', 357 | 'VREX', 'VRM', 'VRNA', 'VRNS', 'VRNT', 'VRP', 'VRRM', 'VRS', 'VRSK', 'VRSN', 'VRT', 'VRTV', 'VRTX', 'VSAT', 'VSEC', 'VSH', 'VSPR', 'VSS', 'VST', 358 | 'VSTM', 'VSTO', 'VT', 'VTC', 'VTEB', 'VTI', 'VTNR', 'VTOL', 'VTR', 'VTRS', 'VTV', 'VTWG', 'VTWO', 'VUG', 'VUZI', 'VV', 'VVI', 'VVNT', 'VVPR', 359 | 'VVV', 'VWO', 'VWOB', 'VXF', 'VXRT', 'VXUS', 'VXX', 'VXZ', 'VYGR', 'VYM', 'VYNE', 'VZ', 'W', 'WAB', 'WABC', 'WAFD', 'WAL', 'WASH', 'WAT', 'WATT', 360 | 'WB', 'WBA', 'WBAI', 'WBS', 'WBT', 'WCC', 'WCLD', 'WCN', 'WD', 'WDAY', 'WDC', 'WDFC', 'WDR', 'WEAT', 'WEC', 'WELL', 'WEN', 'WERN', 'WES', 'WETF', 361 | 'WEX', 'WFC', 'WFH', 'WGO', 'WH', 'WHD', 'WHG', 'WHR', 'WIFI', 'WIMI', 'WING', 'WIRE', 'WISH', 'WIT', 'WIX', 'WK', 'WKHS', 'WLDN', 'WLK', 'WLKP', 362 | 'WLL', 'WLTW', 'WM', 'WMB', 'WMC', 'WMG', 'WMK', 'WMS', 'WMT', 'WNC', 'WNEB', 'WNS', 'WOOD', 'WOOF', 'WOR', 'WORK', 'WOW', 'WPC', 'WPG', 'WPM', 363 | 'WPP', 'WPRT', 'WPS', 'WRAP', 'WRB', 'WRE', 'WRI', 'WRK', 'WRLD', 'WSBC', 'WSBF', 'WSC', 'WSFS', 'WSM', 'WSO', 'WSR', 'WST', 'WTBA', 'WTFC', 'WTI', 364 | 'WTRG', 'WTRH', 'WTS', 'WTTR', 'WU', 'WVE', 'WW', 'WWD', 'WWE', 'WWR', 'WWW', 'WY', 'WYNN', 'X', 'XAIR', 'XAR', 'XBI', 'XBIT', 'XEC', 'XEL', 365 | 'XENE', 'XENT', 'XERS', 'XES', 'XHB', 'XHE', 'XHR', 'XIN', 'XL', 'XLB', 'XLC', 'XLE', 'XLF', 'XLI', 'XLK', 'XLNX', 'XLP', 'XLRE', 'XLRN', 'XLU', 366 | 'XLV', 'XLY', 'XM', 'XME', 'XMLV', 'XNCR', 'XNET', 'XOM', 'XONE', 'XOP', 'XP', 'XPEL', 'XPER', 'XPEV', 'XPH', 'XPO', 'XPP', 'XRAY', 'XRT', 'XRX', 367 | 'XSD', 'XSLV', 'XSOE', 'XSPA', 'XT', 'XXII', 'XYL', 'Y', 'YANG', 'YCBD', 'YCL', 'YCS', 'YELL', 'YELP', 'YETI', 'YEXT', 'YGYI', 'YINN', 'YMAB', 368 | 'YMTX', 'YNDX', 'YOLO', 'YORW', 'YPF', 'YRD', 'YSG', 'YUM', 'YUMC', 'YXI', 'YY', 'Z', 'ZBH', 'ZBRA', 'ZDGE', 'ZEN', 'ZEPP', 'ZEUS', 'ZG', 'ZGNX', 369 | 'ZI', 'ZION', 'ZIOP', 'ZIXI', 'ZLAB', 'ZM', 'ZNGA', 'ZNH', 'ZNOG', 'ZNTE', 'ZROZ', 'ZS', 'ZSL', 'ZTO', 'ZTS', 'ZUMZ', 'ZUO', 'ZVO', 'ZYME', 'ZYNE', 'ZYXI', ] 370 | ''' 371 | 372 | 373 | def human_time(epoch): 374 | new_time = datetime.fromtimestamp(int(epoch) / 1000) 375 | output = new_time.strftime('%Y-%m-%d %H:%M:%S') 376 | 377 | return output 378 | 379 | 380 | def get_time_now(): 381 | curr_time = time.localtime() 382 | curr_clock = time.strftime("%H:%M:%S", curr_time) 383 | curr_m = time.strftime('%m') 384 | curr_y_d = time.strftime('%d%Y') 385 | 386 | int_curr_clock = int(f'{curr_clock[:2]}{curr_clock[3:5]}') 387 | 388 | return int_curr_clock, curr_m, curr_y_d 389 | 390 | 391 | def all_fridays(year): 392 | return pd.date_range(start=str(year), end=str(year+1), 393 | freq='W-FRI').strftime('%m/%d/%Y').tolist() 394 | 395 | 396 | def last_chain(weeks_out): # returns the date to put into lookup_chain 397 | today = str(date.today().strftime("%m/%d/%Y")) 398 | year = today[-4:] 399 | x_days = all_fridays(int(year))[:52] 400 | 401 | fri_count = 0 402 | 403 | for i in x_days: 404 | if today < i: 405 | fri_count = fri_count + 1 406 | if fri_count == weeks_out: 407 | return f'{i[-4:]}-{i[:2]}-{i[3:5]}' 408 | 409 | if fri_count < 5: 410 | y_days = all_fridays(year + 1)[:52] 411 | for i in y_days: 412 | if today < i: 413 | fri_count = fri_count + 1 414 | if fri_count == weeks_out: 415 | return f'{i[-4:]}-{i[:2]}-{i[3:5]}' 416 | 417 | 418 | def get_chain(stock): 419 | global to_date 420 | 421 | opt_lookup = TDSession.get_options_chain( 422 | option_chain={'symbol': stock, 'strikeCount': 50, 423 | 'toDate': to_date}) 424 | 425 | return opt_lookup 426 | 427 | 428 | def raw_chain(raw, put_call): 429 | cp = f'{put_call}ExpDateMap' 430 | raw_data = [[]] 431 | r = -1 432 | for k in raw[cp].keys(): 433 | for strike in raw[cp][k].keys(): 434 | for attr in raw[cp][k][strike][0].keys(): 435 | 436 | unit = raw[cp][k][strike][0][attr] 437 | if unit == put_call.upper(): 438 | r = r + 1 439 | if r > 0: 440 | raw_data.append([]) 441 | 442 | raw_data[r].append(unit) 443 | 444 | return raw_data 445 | 446 | 447 | def clean_chain(raw): 448 | df_cp = pd.DataFrame(raw, columns=opt_column_names) 449 | clean = df_cp.drop(columns=columns_unwanted) 450 | 451 | return clean 452 | 453 | 454 | pulls = 0 455 | failed_pulls = 0 456 | 457 | 458 | def get_next_chains(): 459 | x = 0 460 | global pulls 461 | global failed_pulls 462 | 463 | for stock in stocks: 464 | error = False 465 | try: 466 | chain = get_chain(stock) 467 | except (exceptions.ServerError, exceptions.GeneralError, exceptions.ExdLmtError): 468 | error = True 469 | failed_pulls = failed_pulls + 1 470 | print('A server error occurred') 471 | 472 | if not error: 473 | try: 474 | working_call_data = clean_chain(raw_chain(chain, 'call')) 475 | add_rows(working_call_data, f'c{stock}') 476 | 477 | # print(working_call_data) UNCOMMENT to see working call data 478 | 479 | pulls = pulls + 1 480 | 481 | except ValueError: 482 | print(f'{x}: Calls for {stock} did not have values for this iteration') 483 | failed_pulls = failed_pulls + 1 484 | 485 | try: 486 | working_put_data = clean_chain(raw_chain(chain, 'put')) 487 | add_rows(working_call_data, f'p{stock}') 488 | 489 | # print(working_put_data) UNCOMMENT to see working put data 490 | 491 | pulls = pulls + 1 492 | 493 | except ValueError: 494 | print(f'{x}: Puts for {stock} did not have values for this iteration') 495 | failed_pulls = failed_pulls + 1 496 | 497 | print(f'{x}: {stock}') 498 | x = x + 1 499 | time.sleep(2) 500 | 501 | return 0 502 | 503 | 504 | def main(): 505 | 506 | global file_date, to_date 507 | 508 | to_date = str(last_chain(5)) # specify how many weeks of contracts you want for each pull 509 | t, mon, day = get_time_now() 510 | month = list(trade_days_2021.keys())[int(mon) - 1] 511 | 512 | while True: 513 | t, mon, day = get_time_now() 514 | if (t < 930) or (t > 1600): 515 | print(f'{t}: Market closed {month}{day}'.upper()) 516 | 517 | time.sleep(15) 518 | else: 519 | break 520 | 521 | file_date = f'{month}{day}' 522 | pull_count = 0 523 | end_t = 1600 524 | 525 | while get_time_now()[0] < end_t: 526 | get_next_chains() 527 | pull_count = pull_count + 1 528 | print(pull_count) 529 | 530 | print('option market closed') 531 | print(f'failed_pulls: {failed_pulls}') 532 | print(f'pulls: {pulls}') 533 | 534 | return 0 535 | 536 | 537 | main() 538 | 539 | 540 | # |SQLite management| # 541 | # 542 | # make_sqlite_table('calls') # inputs: puts|calls 543 | # make_sqlite_table('puts') # inputs: puts|calls 544 | # delete_db_table('calls') 545 | # delete_db_table('puts') 546 | # show_db_table('calls') 547 | # show_db_table('puts') 548 | # add_rows(clean_chain(raw_chain(get_chain('SPY'), 'put')), 'puts') # raw_chain(,'put|call')), 'puts|calls') 549 | # delete_row('puts', '', 1321354652) 550 | --------------------------------------------------------------------------------