Hi,
I recently wrote some piece of code to visualize order book in a TT like style. Feel free to comment on it or add something valuable and, most important, please correct me if I made any errors in coding, so the ladder can run faster or more efficient.
Maybe this could be attached to OQ as a sample code.
All the best
Martin
P.S. This works only if you have access to order book data (i.e. TTFIX).
Here is the code (sorry for minimum amount of comments):
Code:
using System;
using System.Drawing;
using System.Collections.Generic;
using System.Timers;
using OpenQuant.API;
using OpenQuant.API.Indicators;
using System.Xml;
using System.ComponentModel;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Reflection;
using System.Threading;
namespace Strat
{
public class MyStrategy : Strategy
{
public delegate void updateGridCallback(DataTable tbl);
RunForm runForm;
Thread oThread;
public bool canGo = false;
int currVol = 0;
int cumVol = 0;
DataTable tbl = new DataTable();
DataRow t;
DataView vtbl;
private static int queueSize = 10000;
private Dictionary<double, Queue<int>> dqBidVol = new
Dictionary<double, Queue<int>>();
private Dictionary<double, Queue<int>> dqAskVol = new
Dictionary<double, Queue<int>>();
private Dictionary<double, Queue<int>> dqTradedVol = new
Dictionary<double, Queue<int>>();
private Dictionary<double, int> bidOrderList = new
Dictionary<double, int>();
private Dictionary<double, int> askOrderList = new
Dictionary<double, int>();
private Queue<int> qBidVol = new Queue<int>(queueSize);
private Queue<int> qAskVol = new Queue<int>(queueSize);
private Queue<int> qTradedVol = new Queue<int>(queueSize);
double p; // traded price
int v; // traded volume
double volAvg;
int tp; // row number of currently traded price
int ptp; // row number of previously traded price
Stopwatch sw = new Stopwatch();
Stopwatch swt = new Stopwatch();
public override void OnStrategyStart()
{
tbl.Columns.Add("Bid", typeof(int));
tbl.Columns.Add("Price", typeof(System.Decimal));
DataColumn[] PrimaryKeyColumns = new DataColumn[1];
PrimaryKeyColumns[0] = tbl.Columns["Price"];
tbl.PrimaryKey = PrimaryKeyColumns;
tbl.Columns.Add("Ask", typeof(int));
tbl.Columns.Add("Curr Volume", typeof(int));
tbl.Columns.Add("Cum Volume", typeof(int));
vtbl = new DataView(tbl);
vtbl.Sort = "Price DESC";
runForm = new RunForm();
oThread = new Thread(new ThreadStart(runForm.startForm));
oThread.Start();
canGo = true;
Thread.Sleep(2000);
runForm.sampleForm.Invoke(runForm.sampleForm.dDelegateInitializeGrid,
vtbl);
if (Instrument.TickSize < 1)
runForm.sampleForm.dataGridView1.Columns["Price"].DefaultCellStyle.Format = "0.00";
else
runForm.sampleForm.dataGridView1.Columns["Price"].DefaultCellStyle.Format = "0";
runForm.sampleForm.Name = Instrument.Symbol.ToString();
runForm.sampleForm.Text = Instrument.Symbol.ToString();
}
public override void OnTrade(Trade trade)
{
swt.Start();
p = trade.Price;
v = trade.Size;
if (Trades.Count > 2)
{
if (p==Trades[Trades.Count-2].Price)
currVol = currVol+v;
else
currVol = v;
}
t = tbl.Rows.Find(p);
if (t != null)
{
t["Curr Volume"] = currVol;
if (t["Cum Volume"] != DBNull.Value)
{
cumVol = (int)t["Cum Volume"];
t["Cum Volume"] = cumVol+v;
}
else
t["Cum Volume"] = v;
}
else
{
DataRow tRow = tbl.NewRow();
tRow["Price"] = p;
tRow["Cum Volume"] = v;
tbl.Rows.Add(tRow);
}
tp = vtbl.Find(p);
if (Trades.Count == 1)
ptp = tp;
runForm.sampleForm.Invoke(runForm.sampleForm.dDelegateUpdateTradePrice, new Object[]{tp, ptp});
ptp = tp;
Console.WriteLine("Trade: " + swt.Elapsed);
swt.Reset();
}
public override void OnOrderBookChanged(OrderBookUpdate update)
{
Console.WriteLine(update.Action.ToString());
t = tbl.Rows.Find(update.Price);
if (update.Action == OrderBookAction.Insert)
{
if (t == null && update.Side == BidAsk.Bid)
{
if (update.Price != null)
tbl.Rows.Add(update.Size, update.Price,
DBNull.Value);
}else if (t == null && update.Side == BidAsk.Ask)
{
if (update.Price != null)
tbl.Rows.Add(DBNull.Value, update.Price,
update.Size);
}
}
else if (update.Action == OrderBookAction.Delete)
{
t = tbl.Rows.Find(update.Price);
t["Bid"] = DBNull.Value;
t["Ask"] = DBNull.Value;
}
else if (update.Action == OrderBookAction.Update)
{
#region update the ladder
if (update.Side == BidAsk.Bid)
{
if (t != null)
{
t["Bid"] = update.Size;
t["Ask"] = DBNull.Value;
}
else
tbl.Rows.Add(DBNull.Value, DBNull.Value, update.Size, update.Price,
DBNull.Value, DBNull.Value, DBNull.Value);
}
else if (update.Side == BidAsk.Ask)
{
if (t != null)
{
t["Ask"] = update.Size;
t["Bid"] = DBNull.Value;
}
else
tbl.Rows.Add(DBNull.Value, DBNull.Value, DBNull.Value, update.Price,
update.Size, DBNull.Value, DBNull.Value);
}
#endregion
Console.WriteLine("Order book" + sw.ElapsedMilliseconds);
sw.Reset();
}
}
public override void OnStrategyStop()
{
runForm.stopForm();
}
}
}
namespace Strat
{
public delegate void DelegateInitializeGrid(DataView tbl);
public delegate void DelegateUpdateGrid(int rb, int ra, int srb, int sra);
public delegate void DelegateUpdateTradePrice(int tp, int ptp);
public class RunForm
{
public Form1 sampleForm = null;
public void startForm()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
sampleForm = new Form1();
Application.Run(sampleForm);
sampleForm.Text = "Ladder";
sampleForm.Name = "Ladder";
}
public void stopForm()
{
sampleForm.Dispose();
}
}
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should bedisposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
//aTimer.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 =
new System.Windows.Forms.DataGridViewCellStyle();
//System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
this.dataGridView1 = new System.Windows.Forms.DataGridView();
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
this.SuspendLayout();
//
// dataGridView1
//
this.dataGridView1.AllowUserToAddRows = false;
this.dataGridView1.AllowUserToDeleteRows = false;
this.dataGridView1.AllowUserToResizeColumns = false;
this.dataGridView1.AllowUserToResizeRows = false;
this.dataGridView1.AutoSizeColumnsMode =
System.Windows.Forms.DataGridViewAutoSizeColumnsMode.Fill;
this.dataGridView1.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.dataGridView1.ColumnHeadersHeight = 25;
this.dataGridView1.ColumnHeadersHeightSizeMode =
System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
dataGridViewCellStyle1.Alignment =
System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.Window;
dataGridViewCellStyle1.Font = new System.Drawing.Font("MicrosoftSans Serif", 11F, System.Drawing.FontStyle.Bold,
System.Drawing.GraphicsUnit.Point, ((byte)(238)));
dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.ControlText;
dataGridViewCellStyle1.SelectionBackColor =
System.Drawing.SystemColors.Highlight;
dataGridViewCellStyle1.SelectionForeColor =
System.Drawing.SystemColors.HighlightText;
dataGridViewCellStyle1.WrapMode =
System.Windows.Forms.DataGridViewTriState.False;
this.dataGridView1.DefaultCellStyle = dataGridViewCellStyle1;
this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill;
this.dataGridView1.EnableHeadersVisualStyles = false;
this.dataGridView1.Location = new System.Drawing.Point(0, 0);
this.dataGridView1.Name = "dataGridView1";
this.dataGridView1.ReadOnly = true;
this.dataGridView1.RowHeadersWidthSizeMode =
System.Windows.Forms.DataGridViewRowHeadersWidthSizeMode.DisableResizing;
this.dataGridView1.ScrollBars = System.Windows.Forms.ScrollBars.None;
this.dataGridView1.Size = new System.Drawing.Size(596, 413);
this.dataGridView1.TabIndex = 0;
this.dataGridView1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.dataGridView1_KeyDown);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(596, 413);
this.Controls.Add(this.dataGridView1);
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
this.ResumeLayout(false);
}
#endregion
private void dataGridView1_KeyDown(object sender, KeyEventArgs e)
{
scrollGrid();
}
private void scrollGrid()
{
int halfWay = (dataGridView1.DisplayedRowCount(false)/2);
if (dataGridView1.FirstDisplayedScrollingRowIndex + halfWay> dataGridView1.SelectedCells[0].RowIndex ||
(dataGridView1.FirstDisplayedScrollingRowIndex + dataGridView1.DisplayedRowCount(false)-halfWay) <= dataGridView1.SelectedCells[0].RowIndex)
{
int targetRow = dataGridView1.SelectedCells[0].RowIndex;
targetRow = Math.Max(targetRow-halfWay, 0);
dataGridView1.FirstDisplayedScrollingRowIndex = targetRow;
}
}
private void initializeGrid(DataView lst)
{
SetDoubleBuffered(dataGridView1);
this.dataGridView1.ReadOnly = true;
this.dataGridView1.DataSource = lst;
dataGridView1.Columns["Price"].DefaultCellStyle.BackColor = System.Drawing.Color.DarkGray;
dataGridView1.Columns["Price"].DefaultCellStyle.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter;
dataGridView1.Columns["Price"].DefaultCellStyle.ForeColor =
System.Drawing.Color.White;
dataGridView1.Columns["Bid"].DefaultCellStyle.BackColor =
System.Drawing.Color.Blue;
dataGridView1.Columns["Bid"].DefaultCellStyle.ForeColor =
System.Drawing.Color.White;
dataGridView1.Columns["Bid"].DefaultCellStyle.Alignment =
System.Windows.Forms.DataGridViewContentAlignment.MiddleRight;
dataGridView1.Columns["Ask"].DefaultCellStyle.BackColor =
System.Drawing.Color.Red;
dataGridView1.Columns["Ask"].DefaultCellStyle.ForeColor =
System.Drawing.Color.White;
dataGridView1.Columns["Ask"].DefaultCellStyle.Alignment =
System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
this.dataGridView1.MultiSelect = false;
}
private void updateGrid(int rb, int ra, int srb, int sra)
{
this.dataGridView1.MultiSelect = false;
this.dataGridView1.MultiSelect = true;
this.dataGridView1.Rows[rb].Selected = true;
this.dataGridView1.Rows[ra].Selected = true;
this.dataGridView1.Refresh();
}
private void updateTradePrice(int tp, int ptp)
{
lock(this.dataGridView1)
{
this.dataGridView1.Rows[tp].Cells["Price"].Style.BackColor = Color.Gray;
this.dataGridView1.Rows[tp].Cells["Curr volume"].Selected = true;
this.dataGridView1.Refresh();
}
}
public System.Windows.Forms.DataGridView dataGridView1;
}
public partial class Form1 : Form
{
public bool canGo = false;
public DelegateInitializeGrid dDelegateInitializeGrid;
public DelegateUpdateGrid dDelegateUpdateGrid;
public DelegateUpdateTradePrice dDelegateUpdateTradePrice;
public Form1()
{
InitializeComponent();
dataGridView1.AutoGenerateColumns = true;
dDelegateInitializeGrid = new DelegateInitializeGrid(this.initializeGrid);
dDelegateUpdateGrid = new DelegateUpdateGrid(this.updateGrid);
dDelegateUpdateTradePrice = new DelegateUpdateTradePrice(this.updateTradePrice);
}
public static void SetDoubleBuffered(Control control)
{
// set instance non-public property with name "DoubleBuffered" to true
typeof(Control).InvokeMember("DoubleBuffered",
BindingFlags.SetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
null, control, new object[] { true });
}
}
}