22import threading
33import time
44import datetime
5- import queue
65
76API_KEY = "API_KEY"
87API_SECRET = "API_SECRET"
98APCA_API_BASE_URL = "https://paper-api.alpaca.markets"
109
10+
1111class LongShort :
1212 def __init__ (self ):
13- self .alpaca = tradeapi .REST (API_KEY ,API_SECRET ,APCA_API_BASE_URL ,'v2' )
13+ self .alpaca = tradeapi .REST (API_KEY , API_SECRET , APCA_API_BASE_URL , 'v2' )
1414
15- stockUniverse = ['DOMO' ,'TLRY' ,'SQ' ,'MRO' ,'AAPL' ,'GM' ,'SNAP' ,'SHOP' ,'SPLK' ,'BA' ,'AMZN' ,'SUI' ,'SUN' ,'TSLA' ,'CGC' ,'SPWR' ,'NIO' ,'CAT' ,'MSFT' ,'PANW' ,'OKTA' ,'TWTR' ,'TM' ,'RTN' ,'ATVI' ,'GS' ,'BAC' ,'MS' ,'TWLO' ,'QCOM' ,]
15+ stockUniverse = ['DOMO' , 'TLRY' , 'SQ' , 'MRO' , 'AAPL' , 'GM' , 'SNAP' , 'SHOP' , 'SPLK' , 'BA' , 'AMZN' , 'SUI' , 'SUN' , 'TSLA' , 'CGC' , 'SPWR' , 'NIO' , 'CAT' , 'MSFT' , 'PANW' , 'OKTA' , 'TWTR' , 'TM' , 'RTN' , 'ATVI' , 'GS' , 'BAC' , 'MS' , 'TWLO' , 'QCOM' , ]
1616 # Format the allStocks variable for use in the class.
1717 self .allStocks = []
1818 for stock in stockUniverse :
19- self .allStocks .append ([stock ,0 ])
19+ self .allStocks .append ([stock , 0 ])
2020
2121 self .long = []
2222 self .short = []
@@ -28,13 +28,13 @@ def __init__(self):
2828 self .longAmount = 0
2929 self .shortAmount = 0
3030 self .timeToClose = None
31-
31+
3232 def run (self ):
3333 # First, cancel any existing orders so they don't impact our buying power.
3434 orders = self .alpaca .list_orders (status = "open" )
3535 for order in orders :
3636 self .alpaca .cancel_order (order .id )
37-
37+
3838 # Wait for market to open.
3939 print ("Waiting for market to open..." )
4040 tAMO = threading .Thread (target = self .awaitMarketOpen )
@@ -53,7 +53,7 @@ def run(self):
5353 closingTime = clock .next_close .replace (tzinfo = datetime .timezone .utc ).timestamp ()
5454 currTime = clock .timestamp .replace (tzinfo = datetime .timezone .utc ).timestamp ()
5555 self .timeToClose = closingTime - currTime
56-
56+
5757 if (self .timeToClose < (60 * 15 )):
5858 # Close all positions when 15 minutes til market close.
5959 print ("Market closing soon. Closing positions." )
@@ -66,13 +66,13 @@ def run(self):
6666 orderSide = 'buy'
6767 qty = abs (int (float (position .qty )))
6868 respSO = []
69- tSubmitOrder = threading .Thread (target = self .submitOrder (qty ,position .symbol ,orderSide ,respSO ))
69+ tSubmitOrder = threading .Thread (target = self .submitOrder (qty , position .symbol , orderSide , respSO ))
7070 tSubmitOrder .start ()
7171 tSubmitOrder .join ()
72-
72+
7373 # Run script again after market close for next trading day.
7474 print ("Sleeping until market close (15 minutes)." )
75- time .sleep (60 * 15 )
75+ time .sleep (60 * 15 )
7676 else :
7777 time .sleep (60 )
7878
@@ -83,7 +83,7 @@ def awaitMarketOpen(self):
8383 print ("spinning" )
8484 time .sleep (60 )
8585 isOpen = self .alpaca .get_clock ().is_open
86-
86+
8787 def rebalance (self ):
8888 tRerank = threading .Thread (target = self .rerank )
8989 tRerank .start ()
@@ -94,10 +94,10 @@ def rebalance(self):
9494 for order in orders :
9595 self .alpaca .cancel_order (order .id )
9696
97- print ("We are longing : " + str (self .long ))
98- print ("We are shorting : " + str (self .short ))
97+ print ("We are taking a long position in : " + str (self .long ))
98+ print ("We are taking a short position in : " + str (self .short ))
9999 # Remove positions that are no longer in the short or long list, and make a list of positions that do not need to change. Adjust position quantities if needed.
100- executed = [[],[]]
100+ executed = [[], []]
101101 positions = self .alpaca .list_positions ()
102102 self .blacklist .clear ()
103103 for position in positions :
@@ -110,7 +110,7 @@ def rebalance(self):
110110 else :
111111 side = "buy"
112112 respSO = []
113- tSO = threading .Thread (target = self .submitOrder ,args = [abs (int (float (position .qty ))),position .symbol ,side ,respSO ])
113+ tSO = threading .Thread (target = self .submitOrder , args = [abs (int (float (position .qty ))), position .symbol , side , respSO ])
114114 tSO .start ()
115115 tSO .join ()
116116 else :
@@ -119,7 +119,7 @@ def rebalance(self):
119119 # Position changed from long to short. Clear long position to prepare for short position.
120120 side = "sell"
121121 respSO = []
122- tSO = threading .Thread (target = self .submitOrder ,args = [int (float (position .qty )),position .symbol ,side ,respSO ])
122+ tSO = threading .Thread (target = self .submitOrder , args = [int (float (position .qty )), position .symbol , side , respSO ])
123123 tSO .start ()
124124 tSO .join ()
125125 else :
@@ -136,7 +136,7 @@ def rebalance(self):
136136 # Too little short positions. Sell some more.
137137 side = "sell"
138138 respSO = []
139- tSO = threading .Thread (target = self .submitOrder ,args = [abs (diff ),position .symbol ,side ,respSO ])
139+ tSO = threading .Thread (target = self .submitOrder , args = [abs (diff ), position .symbol , side , respSO ])
140140 tSO .start ()
141141 tSO .join ()
142142 executed [1 ].append (position .symbol )
@@ -146,7 +146,7 @@ def rebalance(self):
146146 if (position .side == "short" ):
147147 # Position changed from short to long. Clear short position to prepare for long position.
148148 respSO = []
149- tSO = threading .Thread (target = self .submitOrder ,args = [abs (int (float (position .qty ))),position .symbol ,"buy" ,respSO ])
149+ tSO = threading .Thread (target = self .submitOrder , args = [abs (int (float (position .qty ))), position .symbol , "buy" , respSO ])
150150 tSO .start ()
151151 tSO .join ()
152152 else :
@@ -163,22 +163,22 @@ def rebalance(self):
163163 # Too little long positions. Buy some more.
164164 side = "buy"
165165 respSO = []
166- tSO = threading .Thread (target = self .submitOrder ,args = [abs (diff ),position .symbol ,side ,respSO ])
166+ tSO = threading .Thread (target = self .submitOrder , args = [abs (diff ), position .symbol , side , respSO ])
167167 tSO .start ()
168168 tSO .join ()
169- executed [0 ].append (position .symbol )
169+ executed [0 ].append (position .symbol )
170170 self .blacklist .add (position .symbol )
171171
172172 # Send orders to all remaining stocks in the long and short list.
173173 respSendBOLong = []
174- tSendBOLong = threading .Thread (target = self .sendBatchOrder ,args = [self .qLong ,self .long ,"buy" ,respSendBOLong ])
174+ tSendBOLong = threading .Thread (target = self .sendBatchOrder , args = [self .qLong , self .long , "buy" , respSendBOLong ])
175175 tSendBOLong .start ()
176176 tSendBOLong .join ()
177177 respSendBOLong [0 ][0 ] += executed [0 ]
178178 if (len (respSendBOLong [0 ][1 ]) > 0 ):
179179 # Handle rejected/incomplete orders and determine new quantities to purchase.
180180 respGetTPLong = []
181- tGetTPLong = threading .Thread (target = self .getTotalPrice ,args = [respSendBOLong [0 ][0 ],respGetTPLong ])
181+ tGetTPLong = threading .Thread (target = self .getTotalPrice , args = [respSendBOLong [0 ][0 ], respGetTPLong ])
182182 tGetTPLong .start ()
183183 tGetTPLong .join ()
184184 if (respGetTPLong [0 ] > 0 ):
@@ -189,14 +189,14 @@ def rebalance(self):
189189 self .adjustedQLong = - 1
190190
191191 respSendBOShort = []
192- tSendBOShort = threading .Thread (target = self .sendBatchOrder ,args = [self .qShort ,self .short ,"sell" ,respSendBOShort ])
192+ tSendBOShort = threading .Thread (target = self .sendBatchOrder , args = [self .qShort , self .short , "sell" , respSendBOShort ])
193193 tSendBOShort .start ()
194194 tSendBOShort .join ()
195195 respSendBOShort [0 ][0 ] += executed [1 ]
196196 if (len (respSendBOShort [0 ][1 ]) > 0 ):
197197 # Handle rejected/incomplete orders and determine new quantities to purchase.
198198 respGetTPShort = []
199- tGetTPShort = threading .Thread (target = self .getTotalPrice ,args = [respSendBOShort [0 ][0 ],respGetTPShort ])
199+ tGetTPShort = threading .Thread (target = self .getTotalPrice , args = [respSendBOShort [0 ][0 ], respGetTPShort ])
200200 tGetTPShort .start ()
201201 tGetTPShort .join ()
202202 if (respGetTPShort [0 ] > 0 ):
@@ -211,15 +211,15 @@ def rebalance(self):
211211 self .qLong = int (self .adjustedQLong - self .qLong )
212212 for stock in respSendBOLong [0 ][0 ]:
213213 respResendBOLong = []
214- tResendBOLong = threading .Thread (target = self .submitOrder ,args = [self .qLong ,stock ,"buy" ,respResendBOLong ])
214+ tResendBOLong = threading .Thread (target = self .submitOrder , args = [self .qLong , stock , "buy" , respResendBOLong ])
215215 tResendBOLong .start ()
216216 tResendBOLong .join ()
217217
218218 if (self .adjustedQShort > - 1 ):
219219 self .qShort = int (self .adjustedQShort - self .qShort )
220220 for stock in respSendBOShort [0 ][0 ]:
221221 respResendBOShort = []
222- tResendBOShort = threading .Thread (target = self .submitOrder ,args = [self .qShort ,stock ,"sell" ,respResendBOShort ])
222+ tResendBOShort = threading .Thread (target = self .submitOrder , args = [self .qShort , stock , "sell" , respResendBOShort ])
223223 tResendBOShort .start ()
224224 tResendBOShort .join ()
225225
@@ -233,64 +233,64 @@ def rerank(self):
233233 longShortAmount = len (self .allStocks ) // 4
234234 self .long = []
235235 self .short = []
236- for i ,stockField in enumerate (self .allStocks ):
236+ for i , stockField in enumerate (self .allStocks ):
237237 if (i < longShortAmount ):
238238 self .short .append (stockField [0 ])
239239 elif (i > (len (self .allStocks ) - 1 - longShortAmount )):
240240 self .long .append (stockField [0 ])
241241 else :
242242 continue
243-
243+
244244 # Determine amount to long/short based on total stock price of each bucket.
245245 equity = int (float (self .alpaca .get_account ().equity ))
246246
247247 self .shortAmount = equity * 0.30
248248 self .longAmount = equity + self .shortAmount
249249
250250 respGetTPLong = []
251- tGetTPLong = threading .Thread (target = self .getTotalPrice ,args = [self .long ,respGetTPLong ])
251+ tGetTPLong = threading .Thread (target = self .getTotalPrice , args = [self .long , respGetTPLong ])
252252 tGetTPLong .start ()
253253 tGetTPLong .join ()
254254
255255 respGetTPShort = []
256- tGetTPShort = threading .Thread (target = self .getTotalPrice ,args = [self .short ,respGetTPShort ])
256+ tGetTPShort = threading .Thread (target = self .getTotalPrice , args = [self .short , respGetTPShort ])
257257 tGetTPShort .start ()
258258 tGetTPShort .join ()
259259
260260 self .qLong = int (self .longAmount // respGetTPLong [0 ])
261261 self .qShort = int (self .shortAmount // respGetTPShort [0 ])
262262
263263 # Get the total price of the array of input stocks.
264- def getTotalPrice (self ,stocks ,resp ):
264+ def getTotalPrice (self , stocks , resp ):
265265 totalPrice = 0
266266 for stock in stocks :
267- bars = self .alpaca .get_barset (stock ,"minute" ,1 )
267+ bars = self .alpaca .get_barset (stock , "minute" , 1 )
268268 totalPrice += bars [stock ][0 ].c
269269 resp .append (totalPrice )
270270
271271 # Submit a batch order that returns completed and uncompleted orders.
272- def sendBatchOrder (self ,qty ,stocks ,side ,resp ):
272+ def sendBatchOrder (self , qty , stocks , side , resp ):
273273 executed = []
274274 incomplete = []
275275 for stock in stocks :
276276 if (self .blacklist .isdisjoint ({stock })):
277277 respSO = []
278- tSubmitOrder = threading .Thread (target = self .submitOrder ,args = [qty ,stock ,side ,respSO ])
278+ tSubmitOrder = threading .Thread (target = self .submitOrder , args = [qty , stock , side , respSO ])
279279 tSubmitOrder .start ()
280280 tSubmitOrder .join ()
281- if (respSO [0 ] == False ):
281+ if (not respSO [0 ]):
282282 # Stock order did not go through, add it to incomplete.
283283 incomplete .append (stock )
284284 else :
285285 executed .append (stock )
286286 respSO .clear ()
287- resp .append ([executed ,incomplete ])
287+ resp .append ([executed , incomplete ])
288288
289289 # Submit an order if quantity is above 0.
290- def submitOrder (self ,qty ,stock ,side ,resp ):
290+ def submitOrder (self , qty , stock , side , resp ):
291291 if (qty > 0 ):
292292 try :
293- self .alpaca .submit_order (stock ,qty ,side ,"market" ,"day" )
293+ self .alpaca .submit_order (stock , qty , side , "market" , "day" )
294294 print ("Market order of " + '|' + str (qty ) + " " + stock + " " + side + '|' + " completed." )
295295 resp .append (True )
296296 except :
@@ -303,9 +303,9 @@ def submitOrder(self,qty,stock,side,resp):
303303 # Get percent changes of the stock prices over the past 10 days.
304304 def getPercentChanges (self ):
305305 length = 10
306- for i ,stock in enumerate (self .allStocks ):
307- bars = self .alpaca .get_barset (stock [0 ],'minute' ,length )
308- self .allStocks [i ][1 ] = (bars [stock [0 ]][len (bars [stock [0 ]])- 1 ].c - bars [stock [0 ]][0 ].o ) / bars [stock [0 ]][0 ].o
306+ for i , stock in enumerate (self .allStocks ):
307+ bars = self .alpaca .get_barset (stock [0 ], 'minute' , length )
308+ self .allStocks [i ][1 ] = (bars [stock [0 ]][len (bars [stock [0 ]]) - 1 ].c - bars [stock [0 ]][0 ].o ) / bars [stock [0 ]][0 ].o
309309
310310 # Mechanism used to rank the stocks, the basis of the Long-Short Equity Strategy.
311311 def rank (self ):
0 commit comments