from ibapi.client import *
from ibapi.wrapper import *
import pandas as pd
import numpy as np
from datetime import datetime as dt
import time
import matplotlib.pyplot as plt
import datetime
import time as tt
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import style
from tkinter import *
from tkinter import ttk
from matplotlib.backends.backend_tkagg import (
FigureCanvasTkAgg, NavigationToolbar2Tk)
import ast
class Trader(EWrapper, EClient):
def __init__(self):
EClient.__init__(self, self)
self.root = Tk()
self.root.title("Trading")
self.root.geometry('1000x800')
self.root.configure(background='#2E3138')
sep = ttk.Separator(self.root,orient=VERTICAL).grid(row = 0, column=4, rowspan=5, sticky='ns')
self.spread = []
self.x_train = []
self.x_shares_list = []
self.y_train = []
self.y_shares_list = []
self.indicator_train = []
self.simple_ma = []
self.upper_bound = []
self.lower_bound = []
self.account_val = []
self.beta_node = 0
self.beta_1 = 0
self.pause_count = 0
self.spread_lag = 10
self.training_period = 50
self.bound_deviations = 2
self.order_id = 1
self.u_pos = False
self.l_pos = False
##### Algo Side ####
self.algo_label = Label(self.root, text='Algo',bg="#2E3138", fg='white', font=("montserrat", 15), bd=0, highlightthickness=0).grid(row=0, column=1,sticky='w', padx=(0,0), pady=(0,0))
self.algo_button ={}
self.algo_button_count = 0
self.algo_running = False
self.algo_button[self.algo_button_count] = Button(self.root, text="Algo", command=self.start_algo, height=1, fg="#2E3138", bg='#e00404',font=("montserrat", 10), bd=0, highlightthickness=0) .grid(row=2, column=3, padx=(5,5),pady=(5,5))
self.symbols_label = Label(self.root, text='Symbols',bg="#2E3138", fg='white', font=("montserrat", 12), bd=0, highlightthickness=0).grid(row=1, column=1,sticky='w', padx=(0,0), pady=(0,0))
self.symbols_entry = Entry(self.root, bg="#23252B", fg='white', font=("montserrat", 15), bd=0, highlightthickness=0, justify='center',width=10)
self.symbols_entry.insert(END,"['IYR','VNQ']")
self.symbols_entry.grid(row=2, column=1, sticky='we', padx=(0,5), pady=(0,0))
self.allocation_label = Label(self.root, text='Allocation',bg="#2E3138", fg='white', font=("montserrat", 12), bd=0, highlightthickness=0).grid(row=1, column=2,sticky='w', padx=(0,0), pady=(0,0))
self.allocation_entry = Entry(self.root, bg="#23252B", fg='white', font=("montserrat", 15), bd=0, highlightthickness=0, justify='center',width=10)
self.allocation_entry.insert(END,"100000")
self.allocation_entry.grid(row=2, column=2, sticky='we', padx=(0,5), pady=(0,0))
##### Manual Side #####
self.manual_label = Label(self.root, text='Manual',bg="#2E3138", fg='white', font=("montserrat", 15), bd=0, highlightthickness=0).grid(row=0, column=5,sticky='w', padx=(0,0), pady=(0,0))
self.feed_button ={}
self.feed_button_count = 0
self.feed_running = False
self.feed_button[self.feed_button_count] = Button(self.root, text="Feed", command=self.start_trading, height=1, fg="#2E3138", bg='#e00404',font=("montserrat", 10), bd=0, highlightthickness=0) .grid(row=2, column=5, padx=(5,5),pady=(5,5))
##### Plots #####
self.fig, (self.ax1,self.ax2,self.ax3,self.ax4) = plt.subplots(4,1,figsize=(10, 7))
self.ax1.set_facecolor('#2E3138')
self.ax1.set_title('X Price',color='white')
self.ax1.tick_params(axis='x', colors='white')
self.ax1.tick_params(axis='y', colors='white')
self.ax2.set_facecolor('#2E3138')
self.ax2.set_title('Y Price',color='white')
self.ax2.tick_params(axis='x', colors='white')
self.ax2.tick_params(axis='y', colors='white')
self.ax3.set_facecolor('#2E3138')
self.ax3.set_title('Spread',color='white')
self.ax3.tick_params(axis='x', colors='white')
self.ax3.tick_params(axis='y', colors='white')
self.ax4.set_facecolor('#2E3138')
self.ax4.set_title('Account Balance',color='white')
self.ax4.tick_params(axis='x', colors='white')
self.ax4.tick_params(axis='y', colors='white')
self.ax4.invert_yaxis()
self.fig.set_facecolor('#2E3138')
self.fig.tight_layout()
self.canvas = FigureCanvasTkAgg(self.fig, master=self.root)
self.canvas.get_tk_widget().place(relx = 0.5, rely = 0.55, anchor = CENTER)
self.canvas.draw()
self.run()
def connect_start(self):
self.connect("127.0.0.1", 4002, 1)
time.sleep(1)
def start_algo(self):
self.algo_button_count += 1
if self.algo_running == False:
self.algo_running = True
self.algo_button[self.algo_button_count] = Button(self.root, text="Algo", command=self.start_algo, height=1, fg="#2E3138", bg='#08e004',font=("montserrat", 10), bd=0, highlightthickness=0) .grid(row=2, column=3, padx=(5,5),pady=(5,5))
elif self.algo_running == True:
self.algo_running = False
self.algo_button[self.algo_button_count] = Button(self.root, text="Algo", command=self.start_algo, height=1, fg="#2E3138", bg='#e00404',font=("montserrat", 10), bd=0, highlightthickness=0) .grid(row=2, column=3, padx=(5,5),pady=(5,5))
def start_trading(self):
self.feed_button_count += 1
if self.feed_running == False:
self.connect_start()
self.feed_running = True
self.feed_button[self.feed_button_count] = Button(self.root, text="Feed", command=self.start_trading, height=1, fg="#2E3138", bg='#08e004',font=("montserrat", 10), bd=0, highlightthickness=0) .grid(row=2, column=5, padx=(5,5),pady=(5,5))
symbols = self.symbols_entry.get()
self.symbols = ast.literal_eval(symbols)
self.starting_balance = int(self.allocation_entry.get())
symbols = ['IYR','VNQ']
starting_balance = 100000
self.balance = starting_balance
self.x_symbol = symbols[0]
self.y_symbol = symbols[1]
id = 1
for symbol in symbols:
contract = self.create_contract(symbol,'STK','SMART','USD','NYSE')
self.reqMktData(id, contract, "236", False, False, [])
id += 1
self.run()
elif self.feed_running == True:
self.disconnect()
self.feed_running = False
self.feed_button[self.feed_button_count] = Button(self.root, text="Feed", command=self.start_trading, height=1, fg="#2E3138", bg='#e00404',font=("montserrat", 10), bd=0, highlightthickness=0) .grid(row=2, column=5, padx=(5,5),pady=(5,5))
def tickPrice(self, reqId , tickType , price: float,attrib ):
super().tickPrice(reqId, tickType, price, attrib)
############ Getting Current Account Value ############
if self.feed_running == True:
if tickType == 2:
if reqId == 1:
if len(self.x_train) != self.training_period:
self.x_train.append(price)
self.ax1.clear()
self.ax1.plot(self.x_train)
elif len(self.x_train) == self.training_period:
self.x_train = self.x_train[1:]
self.x_train.append(price)
self.ax1.clear()
self.ax1.plot(self.x_train)
elif reqId == 2:
if len(self.y_train) != self.training_period:
self.y_train.append(price)
self.ax2.clear()
self.ax2.plot(self.y_train)
elif len(self.y_train) == self.training_period:
self.y_train = self.y_train[1:]
self.y_train.append(price)
self.ax2.clear()
self.ax2.plot(self.y_train)
self.reqAccountSummary(1, "All", "NetLiquidation")
self.fig.canvas.draw()
self.fig.canvas.flush_events()
if len(self.y_train) == self.training_period and len(self.x_train) == self.training_period:
x_bar = sum(self.x_train) / len(self.x_train)
y_bar = sum(self.y_train) / len(self.y_train)
top_sum = 0
bottom_sum = 0
for i,j in zip(self.x_train,self.y_train):
top_sum += (i*x_bar)*(j*y_bar)
bottom_sum += (i*x_bar)**2
self.beta_1 = top_sum/bottom_sum
self.beta_node = y_bar - (self.beta_1*x_bar)
if len(self.indicator_train) == 0:
for x,y in zip(self.x_train,self.y_train):
tick = y - (self.beta_node+(self.beta_1*x))
self.indicator_train.append(tick)
else:
tick = self.y_train[len(self.y_train)-1] - (self.beta_node+(self.beta_1*self.x_train[len(self.x_train)-1]))
self.indicator_train.append(tick)
self.pause_count += 1
############ Spread With Lag To Slow Trades ############
if self.pause_count == self.spread_lag:
tick = self.y_train[len(self.y_train)-1] - (self.beta_node+(self.beta_1*self.x_train[len(self.x_train)-1]))
self.pause_count = 0
self.spread.append(tick)
if len(self.spread) == self.training_period+1:
self.simple_ma = self.simple_ma[1:]
self.upper_bound = self.upper_bound[1:]
self.lower_bound = self.lower_bound[1:]
self.spread = self.spread[1:]
############ Refreshing Bounds ############
# possbily modify to change bounds to use spread once spread is a certain length
sma = sum(self.indicator_train)/len(self.indicator_train)
sd = np.std(self.indicator_train)
upper = sma+(sd*self.bound_deviations)
lower = sma-(sd*self.bound_deviations)
############ Appending To Bounds ############
self.simple_ma.append(sma)
self.upper_bound.append(upper)
self.lower_bound.append(lower)
self.indicator_train = self.indicator_train[self.pause_count:]
############ Updating Plot ############
self.ax3.clear()
self.ax3.plot(self.spread)
self.ax3.plot(self.simple_ma)
self.ax3.plot(self.upper_bound)
self.ax3.plot(self.lower_bound)
############ Setting Cash Balances For X and Y ############
x_cash = (self.balance/(self.beta_1 + 1))*self.beta_1
y_cash = self.balance - x_cash
############ Getting Current Position Values If Positions Are Open ############
if self.l_pos == True and self.spread[len(self.spread)-1] < sma:
self.reqPositions()
if self.u_pos == True and self.spread[len(self.spread)-1] > sma:
self.reqPositions()
############ Opening Upper Position ############
if self.algo_running == True:
if self.u_pos == False and self.spread[len(self.spread)-1] >= upper:
x_shares = round(x_cash / self.x_train[len(self.x_train)-1],0)
x_contract = self.create_contract(self.x_symbol,'STK','SMART','USD','NYSE')
buy_order = self.create_order(self.order_id,'LMT',x_shares,'SELL',self.x_train[len(self.x_train)-1])
self.placeOrder(self.order_id,x_contract,buy_order)
self.order_id += 1
y_shares = round(y_cash / self.y_train[len(self.y_train)-1],0)
y_contract = self.create_contract(self.y_symbol,'STK','SMART','USD','NYSE')
sell_order = self.create_order(self.order_id,'LMT',y_shares,'BUY',self.y_train[len(self.y_train)-1])
self.placeOrder(self.order_id,y_contract,sell_order)
self.order_id += 1
self.x_shares_list.append(x_shares)
self.y_shares_list.append(y_shares)
print ('Opened Upper')
self.u_pos = True
############ Closing Upper Position ############
if self.u_pos == True and self.spread[len(self.spread)-1] <= sma:
x_shares = self.x_shares_list[len(self.x_shares_list)-1]
x_contract = self.create_contract(self.x_symbol,'STK','SMART','USD','NYSE')
buy_order = self.create_order(self.order_id,'LMT',x_shares,'BUY',self.x_train[len(self.x_train)-1]-0.02)
self.placeOrder(self.order_id,x_contract,buy_order)
self.order_id += 1
y_shares = (self.y_shares_list[len(self.y_shares_list)-1])
y_contract = self.create_contract(self.y_symbol,'STK','SMART','USD','NYSE')
sell_order = self.create_order(self.order_id,'LMT',y_shares,'SELL',self.y_train[len(self.y_train)-1]+0.02)
self.placeOrder(self.order_id,y_contract,sell_order)
self.order_id += 1
print ('Closed Upper')
self.u_pos = False
############ Opening Lower Position ############
if self.l_pos == False and self.spread[len(self.spread)-1] <= lower:
x_shares = round(x_cash / self.x_train[len(self.x_train)-1],0)
x_contract = self.create_contract(self.x_symbol,'STK','SMART','USD','NYSE')
buy_order = self.create_order(self.order_id,'LMT',x_shares,'BUY',self.x_train[len(self.x_train)-1])
self.placeOrder(self.order_id,x_contract,buy_order)
self.order_id += 1
y_shares = round(y_cash / self.y_train[len(self.y_train)-1],0)
y_contract = self.create_contract(self.y_symbol,'STK','SMART','USD','NYSE')
sell_order = self.create_order(self.order_id,'LMT',y_shares,'SELL',self.y_train[len(self.y_train)-1])
self.placeOrder(self.order_id,y_contract,sell_order)
self.order_id += 1
self.x_shares_list.append(x_shares)
self.y_shares_list.append(y_shares)
print ('Opened Lower')
self.l_pos = True
############ Closing Lower Position ############
if self.l_pos == True and self.spread[len(self.spread)-1] >= sma:
x_shares = self.x_shares_list[len(self.x_shares_list)-1]
x_contract = self.create_contract(self.x_symbol,'STK','SMART','USD','NYSE')
buy_order = self.create_order(self.order_id,'LMT',x_shares,'SELL',self.x_train[len(self.x_train)-1]+0.02)
self.placeOrder(self.order_id,x_contract,buy_order)
self.order_id += 1
y_shares = self.y_shares_list[len(self.y_shares_list)-1]
y_contract = self.create_contract(self.y_symbol,'STK','SMART','USD','NYSE')
sell_order = self.create_order(self.order_id,'LMT',y_shares,'BUY',self.y_train[len(self.y_train)-1]-0.02)
self.placeOrder(self.order_id,y_contract,sell_order)
self.order_id += 1
print ('Closed Lower')
self.l_pos = False
self.fig.canvas.draw()
self.fig.canvas.flush_events()
def create_contract(self,symbol,secType,exchange,currency,prim):
contract = Contract()
contract.symbol = symbol
contract.secType = secType
contract.exchange = exchange
contract.currency = currency
contract.primaryExchange = prim
return contract
def create_order(self,orderId,order_type,quantity,action,limitPrice):
order = Order()
order.eTradeOnly = ''
order.firmQuoteOnly = ''
order.orderId = orderId
order.action = action
order.orderType = order_type
order.totalQuantity = quantity
order.lmtPrice = limitPrice
return order
def accountSummary(self, reqId: int, account: str, tag: str, value: str, currency: str):
super().accountSummary(reqId, account, tag, value, currency)
self.account_val.append(value)
self.ax4.clear()
self.ax4.plot(self.account_val)
self.fig.canvas.draw()
self.fig.canvas.flush_events()
def accountSummaryEnd(self, reqId: int):
super().accountSummaryEnd(reqId)
def position(self, account: str, contract: Contract, position, avgCost: float):
super().position(account, contract, position, avgCost)
print("Symbol:", contract.symbol, "Position:", position, "Avg cost:", avgCost)
def positionEnd(self):
super().positionEnd()
def openOrder(self,orderId: OrderId,contract: Contract,order: Order, orderStatus: OrderState):
print (f'openOrder. OrderId: {orderId}, contract: {contract}, order: {order}')
def orderStatus(self, orderId: OrderId, status: str, filled: float, remaining: float, avgFillPrice: float, permId: int, parentId: int, lastFillPrice: float, clientId: int, whyHeld: str, mktCapPrice: float):
return super().orderStatus(orderId, status, filled, remaining, avgFillPrice, permId, parentId, lastFillPrice, clientId, whyHeld, mktCapPrice)
def commissionReport(self, commissionReport: CommissionReport):
super().commissionReport(commissionReport)
print("Realized P&L:", commissionReport.realizedPNL, 'Commission:',commissionReport.commission)
def start(self):
self.root.mainloop()
self.run()
#Trader().start()
Trader().start()