Monday, 1 June 2020

Trading Platform in C# Part 1 - Connect to TWS API

Create a trading platform in C#

Write a Windows form program in C# using Visual Studio and connect to Interactive Brokers Application Program Interface. I prefer writing GUI apps and not console apps. Other things you will need to do is sign up for a trial version of the Interactive Brokers trading software, if you already have an account with Interactive Brokers then great 

 

 

You will need to install 3 different software applications

 

Links to the programs that you need to install
Visual Studio 
https://visualstudio.microsoft.com/downloads/

Interactive Brokers Traders Workstation trading platform 
https://www.interactivebrokers.com/en/index.php?f=15876


Interactive Brokers API 
https://www.interactivebrokers.com/en/index.php?f=5041

Once you have downloaded and installed the above software you are ready to get started



# Control Name Text or Value
1 Button
btnConnect Connect
2 Combobox cbSymbol
MSFT
3 Listbox
lbData


Place this on line 19 in the EWrapperImpl.cs file


public Form1 myform;

Place the highlighted text in the tickPrice method within the EWrapperImpl.cs file


public virtual void tickPrice(int tickerId, int field, double price, TickAttrib attribs) 
        {
            Console.WriteLine("Tick Price. Ticker Id:" +tickerId+ ", Field: "+field+", Price: "+price+", CanAutoExecute: "+attribs.CanAutoExecute + 
                ", PastLimit: " + attribs.PastLimit + ", PreOpen: " + attribs.PreOpen);

            string strData = "Tick Price. Ticker Id:" + tickerId + ", Field: " + field +
                      ", Price: " + price + ", CanAutoExecute: " + attribs.CanAutoExecute;

            
            // Add this tick price to the form by calling the AddListBoxItem delegate
            myform.AddListBoxItem(strData);



        }

This is how the Form1.cs file should look.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using IBApi;

namespace IB_TradingPlatform
{
    public partial class Form1 : Form
    {
        // This delegate enables asynchronous calls for setting
        // the text property on a ListBox control.
        delegate void SetTextCallback(string text);

        public void AddListBoxItem(string text)
        {
            // See if a new invocation is required form a different thread            
            if (this.lbData.InvokeRequired)            
            {
                SetTextCallback d = new SetTextCallback(AddListBoxItem);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                // Add the text string to the list box
                this.lbData.Items.Add(text);
            }
        }

        // Create the ibClient object to represent the connection
        IB_TradingPlatform.EWrapperImpl ibClient;

        public Form1()
        {
            InitializeComponent();

            // instantiate the ibClient
            ibClient = new IB_TradingPlatform.EWrapperImpl();
        }

        private void btnConnect_Click(object sender, EventArgs e)
        {
            // Parameters to connect to TWS are:
            // host       - IP address or host name of the host running TWS
            // port       - listening port 7496 or 7497
            // clientId   - client application identifier can be any number
            ibClient.ClientSocket.eConnect("", 7497, 0);

            var reader = new EReader(ibClient.ClientSocket, ibClient.Signal);
            reader.Start();
            new Thread(() => {
                while (ibClient.ClientSocket.IsConnected())
                {
                    ibClient.Signal.waitForSignal();
                    reader.processMsgs();
                }
            })
            { IsBackground = true }.Start();
            // Wait until the connection is completed
            while (ibClient.NextOrderId <= 0) { }

            // Set up the form object in the EWrapper
            ibClient.myform = (Form1)Application.OpenForms[0];

            getData();
        }

        private void getData()
        {
            ibClient.ClientSocket.cancelMktData(1); // cancel market data

            // Create a new contract to specify the security we are searching for
            IBApi.Contract contract = new IBApi.Contract();
            // Create a new TagValueList object (for API version 9.71 and later) 
            List<IBApi.TagValue> mktDataOptions = new List<IBApi.TagValue>();

            // Set the underlying stock symbol fromthe cbSymbol combobox            
            contract.Symbol = cbSymbol.Text;
            // Set the Security type to STK for a Stock
            contract.SecType = "STK";
            // Use "SMART" as the general exchange
            contract.Exchange = "SMART";
            // Set the primary exchange (sometimes called Listing exchange)
            // Use either NYSE or ISLAND
            contract.PrimaryExch = "ISLAND";
            // Set the currency to USD
            contract.Currency = "USD";

            // If using delayed market data subscription un-comment 
            // the line below to request delayed data
            ibClient.ClientSocket.reqMarketDataType(3);  // delayed data = 3 live = 1

            // Kick off the subscription for real-time data (add the mktDataOptions list for API v9.71)
            
            // For API v9.72 and higher, add one more parameter for regulatory snapshot
            ibClient.ClientSocket.reqMktData(1, contract, "", false, false, mktDataOptions);
        }  
    }
}

Sunday, 10 February 2019

Change color heading of a treeview widget in Python 3


This is the code for changing the color heading in a Treeview Widget



        style = ttk.Style()
        style.element_create("Custom.Treeheading.border", "from", "default")
        style.layout("Custom.Treeview.Heading", [
            ("Custom.Treeheading.cell", {'sticky': 'nswe'}),
            ("Custom.Treeheading.border", {'sticky':'nswe', 'children': [
                ("Custom.Treeheading.padding", {'sticky':'nswe', 'children': [
                    ("Custom.Treeheading.image", {'side':'right', 'sticky':''}),
                    ("Custom.Treeheading.text", {'sticky':'we'})
                ]})
            ]}),
        ])
        style.configure("Custom.Treeview.Heading",
            background="green", foreground="white", relief="flat")
        style.map("Custom.Treeview.Heading",
            relief=[('active','groove'),('pressed','sunken')])

        # create Treeview datagridview
        self.tv = ttk.Treeview(self,  height=8, style= "Custom.Treeview")
        #self.tv.grid(row=3, column=0)
        self.tv['columns'] = ('id', 'symbol', 'price', 'trigger', 'shares', 'side', 'type', 'status', 'fill')
        self.tv.heading("#0", text='Time', anchor='w')
        self.tv.column("#0", stretch=NO, width=5, anchor="w")
        self.tv.heading('id', text='ID')
        self.tv.column('id', anchor='center', width=70)
        self.tv.heading('symbol', text='Symbol')
        self.tv.column('symbol', anchor='center', width=70)
        self.tv.heading('price', text='Price')
        self.tv.column('price', anchor='center', width=70)
        self.tv.heading('trigger', text='Trigger')
        self.tv.column('trigger', anchor='center', width=70)
        self.tv.heading('shares', text='Shares')
        self.tv.column('shares', anchor='center', width=100)
        self.tv.heading('side', text='Side')
        self.tv.column('side', anchor='center', width=70)
        self.tv.heading('type', text='Type')
        self.tv.column('type', anchor='center', width=70)
        self.tv.heading('status', text='Status')
        self.tv.column('status', anchor='center', width=100)
        self.tv.heading('fill', text='Fill')
        self.tv.column('fill', anchor='center', width=70)
        self.tv.bind('<ButtonRelease-1>', self.select_Item) 
        self.tv.grid(row=1, column=0, columnspan=6, padx=5, pady=5)
        self.treeview = self.tv

Sunday, 4 February 2018

Python Button Tkinter passing arguments

Python tkinter button widget passing arguments.  In these examples I will show you several ways you can pass values, variables, arguments to a function. You will also learn how to add a right mouse click as well as the left mouse click.  

Save Save
Here is the code to start the tutorial and follow along
from tkinter import *
from tkinter import ttk

class Application(Frame):
    
    """ A GUI application """

    def __init__(self, master):
        """ Initialize the Frame"""
        ttk.Frame.__init__(self, master)

        self.grid()
        self.create_widgets()

    def create_widgets(self):
        # create a normal button
        self.button1 = Button(root, font=('', 16, 'bold'), text='.22 Cents', command=self.do_something)
        self.button1.grid(row=0, column=0, pady=5, padx=5)

        # create a text box (Entry box) to hold the value of the click event
        self.tbValue = Entry(root, font=('', 16, 'bold'), textvariable=varEntryValue).grid(row=1, column=2, pady=5, padx=5)

        # create a text box (Entry box) to hold a average price
        self.tbSet = Entry(root, font=('', 16, 'bold'), textvariable=varAvgPrice).grid(row=1, column=1, pady=5, padx=5)
        
    # button 1 example
    def button1_Click(event, arg):
        average_Price = varAvgPrice.get() # gets a value from the first Entry box
        c = float(average_Price) + arg # adds the value from the ttk .22 button to the first entry box value
        c = round(c, 2) # round off c to 2 decimal places
        varEntryValue.set(c) # sets the value in the second Entry box

    def do_something(self):
        varEntryValue.set('Hello, Hola, Bonjour')    

root = Tk()

root.title("Button Examples in Python")
root.geometry("790x850")
root.attributes("-topmost", True)
varEntryValue = StringVar()
varAvgPrice = StringVar(root, value='105.00')

app = Application(root)

root.mainloop()



Get The Unique id conId Number from TWS

Learn how to get the unique id (conId) from Interactive brokers using a gui application. Every option has a different number since there are so many variations. The contract id (conid) is a number not a symbol, and this number you will need in order to trade options. For example the IBM 170 CALL option with an expiry on January 6, 2017 has a unique id number of  256910869. The number may be different on the next trading day.  I am not sure if they stay the same from now, until the next day until they expire. You can search for a contract id number here: https://pennies.interactivebrokers.com/cstools/contract_info/v3.9/index.php see the code here To access a September 2016 $40 Call option on Netflix : I believe there is a data fee for options. You need to pay for a data feed for the options in order to request data through the API
conID = 3 # Contract ID
symbol = "NFLX" # Netflix’s stock symbol
secType = "OPT" # Security type is an Option (OPT)
expiry = "20170120" # January 2017 Expiry format yyyymmdd
strike = 90 # $90.00 strike price
right = "CALL" # Call option
multiplier = "100" # multiplier 100 shares per contract for options
exchange = "SMART" # Use IB’s Smart Order router to get the prices
currency = "USD" # USD Currency

To access a June 2017 Crude Oil Futures contract set the properties:
conID = 2 # Contract Id
symbol = "CL" # Crude Oil underlying symbol (CL)
secType = "FUT" # Security type is an Future (FUT)
expiry = "20170120" # January 20, 2017 Expiry third Friday of month
exchange = "NYMEX" # Use IB’s Smart Order router to get the prices
To access a foreign exchange quote such as Euro/USD:
conID = 6 # Contract Id
symbol = "EUR" # Euro underlying (base currency) symbol (EUR/USD quote)
secType = "CASH" # Security type is Cash / FX
exchange = "IDEALPRO" # Use the IDEALPRO FX data source
currency = "USD" # Quoted currency is USD
 
Save Save

Listbox Scroll bars Horizontal Vertical

Listbox Scroll bars tkinter Python Copy and paste the highlighted text into the section of your code where you create your widgets, and also add the x and yscrollcommands to the listbox parameters.
# Craig Hammond 2017
# www.sharpertradingimage.com
        # create scroll bars for your listbox
        self.scrollbar_V = Scrollbar(self)
        self.scrollbar_H = Scrollbar(self, orient=HORIZONTAL)
        self.scrollbar_V.grid(row=1, column=1, sticky=N+S+W)
        self.scrollbar_H.grid(row=5, column=0, sticky=N+E+S+W)
        
        # create listbox widget
        self.listbox1 = Listbox(self, font=('', 12), width=15, height=10, yscrollcommand=self.scrollbar_V.set, xscrollcommand=self.scrollbar_H.set)
        self.listbox1.bind('<<ListboxSelect>>', self.select_item)
        self.listbox1.insert(1, 'FB')
        self.listbox1.grid(row=1, column=0)
        # add some text to the listbox 
        evil_corporations = ['EVIL CORPORATIONS y gobiernos', 'cranAAPLe', 'SBUckX', 'XOMobil',
                                  'Any oil company that you care to name',
                                  'OPECs', 'MSFaT', 'AMEXica', 'ALL COUNTRIES THAT DO NOT PROSECUTE THE BANKERS',
                                  'most TRADING FIRMS', 'BUT NOT INTERACTIVE BROKERS BEST COMMISSIONS not as bad',
                                  'banking cartels, the FED', 'las paisas que le gusta la guerra', 'foundations created by evil elitists']
        for evil in evil_corporations:
            self.listbox1.insert('end', evil)
        # also needed for scroll bars
        self.scrollbar_V.config(command=self.listbox1.yview)
        self.scrollbar_H.config(command=self.listbox1.xview)

Python Treeview delete rows

from tkinter import *
from tkinter import ttk

class Application(Frame):
    
    def __init__(self, master):
        """ Initialize the Frame"""
        ttk.Frame.__init__(self, master)
 
        self.grid()
        self.create_widgets()

    def create_widgets(self):
        self.btnConnect = ttk.Button(self, text = "Search Symbol", command=self.search_symbol).grid(row=0, column=0, sticky=W)
        self.btnDisconnect = ttk.Button(self, text = "Add data", command=self.add_data).grid(row=0, column=1, sticky=W)
        self.btnCancelMktData = ttk.Button(self, text = 'Remove All', command=self.remove_all).grid(row=0, column=2, sticky=W)
        self.button_edit = Button(self, font=('',12), text="select row", width=7, command=self.add_data)
        self.button_edit.grid(row=0, column=4)
        
        # create Treeview widget to hold values in a table
        self.tv = ttk.Treeview(root)    

        # create Treeview 
        self.tv = ttk.Treeview(self,  height=8)
        self.tv['columns'] = ('id', 'symbol', 'price', 'trigger', 'shares', 'side', 'type', 'status', 'fill')
        self.tv.heading("#0", text='Time', anchor='w')
        self.tv.column("#0", stretch=NO, width=5, anchor="w")
        self.tv.heading('id', text='ID')
        self.tv.column('id', anchor='center', width=70)
        self.tv.heading('symbol', text='Symbol')
        self.tv.column('symbol', anchor='center', width=70)
        self.tv.heading('price', text='Price')
        self.tv.column('price', anchor='center', width=70)
        self.tv.heading('trigger', text='Trigger')
        self.tv.column('trigger', anchor='center', width=70)
        self.tv.heading('shares', text='Shares')
        self.tv.column('shares', anchor='center', width=100)
        self.tv.heading('side', text='Side')
        self.tv.column('side', anchor='center', width=70)
        self.tv.heading('type', text='Type')
        self.tv.column('type', anchor='center', width=70)
        self.tv.heading('status', text='Status')
        self.tv.column('status', anchor='center', width=100)
        self.tv.heading('fill', text='Fill')
        self.tv.column('fill', anchor='center', width=70)
        self.tv.bind('<ButtonRelease-1>', self.select_item) 
        self.tv.grid(row=1, column=0, columnspan=6, padx=5, pady=5)
        self.treeview = self.tv
##        self.ysb = ttk.Scrollbar(self, orient='vertical', command=self.tv.yview)
##        self.xsb = ttk.Scrollbar(self, orient='horizontal', command=self.tv.xview)
##        self.tv.configure(yscroll=self.ysb.set, xscroll=self.xsb.set)
##        self.ysb.grid(row=1, column=7, sticky='ns')
##        self.xsb.grid(row=2, column=0, sticky='ew')
        
        ttk.Style().configure("Treeview", font= ('', 11), background="#383838", 
        foreground="white", fieldbackground="yellow")

        self.tv.insert("","end",text = "Person",values = ("1254","MSFT","39.39", "", "0/200", "BUY", "LMT", "Filled", "39.39"), tags='hot')
        self.tv.insert("","end",text = "Animal",values = ("1255","MSFT","39.58", ".10", "0/200", "SELL", "TRAIL", "PreSubmitted", "0.00"), tags='cold')
        self.tv.insert("","end",text = "Name",values = ("1256","MSFT","39.58", "", "0/200", "SELL", "LMT", "Submitted", "0.00"), tags='pizza')
        self.tv.insert("","end",text = "Evil Corp",values = ("1258","NFLX","102.55", "", "0/300", "SELL", "LMT", "Submitted", "0.00"), tags='tacos')

    def remove_all(self):
        x = self.tv.get_children()
        print ('get_children values: ', x ,'\n')
        if x != '()': # checks if there is something in the first row
            for child in x:
                self.tv.delete(child)
                
    def search_symbol(self):
        pass

    def add_data(self):
        pass

    def select_item():
        pass

root = Tk()       
app = Application(root)
root.mainloop()


Save Save

Saturday, 3 February 2018

Scrolling 2 text widgets together

I am using the pack() Geometry Manager to place all of the widgets. I opted for the pack() Manager because it is ideal for placing widgets side by side or drop down position. Fortunately, in a text editor, I have all the widgets Placed next to each other or in descending order. It is therefore advantageous to the pack() Manager. We can do the same with the grid() manager also.

Save Save

# Craig Hammond 2018

import tkinter as tk
from tkinter import *


from tkinter import ttk
import re

class SampleTextApp(Frame):
    def __init__(self, master, **kwargs):# this **kwargs is needed for the scroll bar
        ttk.Frame.__init__(self, master)
        self.file_name = None
        self.grid()
        self.create_widgets()

    def create_widgets(self):

        # font varialble to use with all widgets
        my_font = ('', 18)
        
        # add a text box for the line numbers
        self.line_number_text = Text(self, font=my_font, width=4, padx=3, takefocus=0, border=0, background='yellow', state='disabled', wrap='none')
        self.line_number_text.pack(side='left', fill='y')
        
        # add the main text box widget here
        self.main_text = Text(self, font=my_font, wrap='none')
        self.main_text.bind('<KeyPress>', self.on_text_changed)
        self.main_text.pack(expand='yes', fill='both')
        
        # add a scroll bar for the main text widget
        self.scroll_bar = Scrollbar(self.main_text)
        self.scroll_bar.pack(side='right', fill='y')

        # call the scroll bar functions
        self.scroll_bar['command'] = self.on_scrollbar
        self.line_number_text['yscrollcommand'] = self.on_textscroll
        self.main_text['yscrollcommand'] = self.on_textscroll
# this will update the line numbers any time you
        # press a key on the keyboard
        self.main_text.bind('<Any-KeyPress>', self.on_text_changed)
        self.main_text.focus_set()
   
    def on_scrollbar(self, *args):
        self.line_number_text.yview(*args)
        self.main_text.yview(*args)
        
    def on_textscroll(self, *args):
        # Moves scrollbar and scrolls text widgets when the mouse wheel
        # is moved on the text widget
        self.scroll_bar.set(*args)
        self.on_scrollbar('moveto', args[0])
        
    def on_text_changed(self, event=None):
        self.update_line_numbers()
    
    def get_line_numbers(self):
        output = ''
        row, col = self.main_text.index("end").split('.')
        for i in range(1, int(row)):
            output += str(i) + '\n'
        return output

    def update_line_numbers(self, event=None):
        line_numbers = self.get_line_numbers()
        # disables the text widget so the widget does not scroll
        self.main_text.config(state='disabled')
        self.line_number_text.config(state='normal') 
        self.line_number_text.delete('1.0', 'end')
        self.line_number_text.insert('1.0', line_numbers)
        self.line_number_text.config(state='disabled')
        # returns the text widget back to normal
        self.main_text.config(state='normal')

root = Tk()
PROGRAM_NAME = ' My Text Editor '
root.title(PROGRAM_NAME)
root.geometry("600x300")
app = SampleTextApp(root)
app.pack(fill='both', expand='yes')
app.mainloop()