OpenQuant runs one instance of a strategy per instrument. This concept simplifies strategy development a lot since you always refer to one instrument (Strategy.Instrument) in your code and don't need to maintain arrays and tables holding different values (for example indicator) per instrument. It works pretty well for instrument independent staregies, i.e. for strategies that can run with one instrument, for example trend following or swing trading strategies, but you need to utilize certain techniques if you want to develop strategies that depend on two or more instruments, for example spread, pair trading. market neutral or correlation based strategies.
Assume we want to develop a strategy that buys qty of MSFT and sells qty of AAPL if MSFT / AAPL price ratio becomes larger that certain number X.
Code:
OnBar(Bar bar)
{
Instrument instrument = Instruments["MSFT"];
if (nstrument.Bar.Close / bar.Close > X)
{
Buy(qty);
Sell(instrument, qty);
}
}
You can also define instruments in the header of your strategy to speed things up
Code:
Instrument instrument1 = InstrumentManager.Instruments["MSFT"];
Instrument instrument2 = InstrumentManager.Instruments["AAPL"];
OnQuote(Quote quote)
{
if (Instrument == instrument1)
if (quote.Ask > instrument2.Quote.Bid * delta)
{
Buy(instrument1, qty);
Sell(instrument2, qty);
}
}
Note that you can also use OnBarSlice event handler.
Quote:
OnBarSlice fires whenever the market data provider BarFactory has finished emitting new bars for all the instruments in the current portfolio. BarFactory emits new bars sequentially when multiple instruments are being traded—first a bar for instrument 1, then a bar for instrument 2, and so on. After all individual bars have been emitted, BarFactory will fire OnBarSlice to tell strategy components that the end of the instrument list has been reached, and that all new bars for the current bar interval have been emitted. OnBarSlice solves the problem of strategy code not knowing when all the instrument bars for a correlation strategy are present and ready to be used. For example, if you try to do correlation calculations in the OnBar event handler for multiple instruments, your code will have to keep track of which instruments have been seen in the OnBar handler for the current bar time interval.
Code:
using System;
using System.Drawing;
using OpenQuant.API;
using OpenQuant.API.Indicators;
public class MyStrategy : Strategy
{
Instrument DELL;
Instrument CSCO;
TimeSeries spread_series;
[Parameter("Order quantity (number of contracts to trade)")]
double Qty = 100;
[Parameter("Length of SMA")]
int SMALength = 20;
[Parameter("Order of BBU")]
double BBUOrder = 2;
[Parameter("Order of BBL")]
double BBLOrder = 2;
// indicators
BBU bbu;
BBL bbl;
SMA sma;
public override void OnStrategyStart()
{
DELL = Instruments["DELL"];
CSCO = Instruments["CSCO"];
spread_series = new TimeSeries("DELL - CSCO", Color.Pink);
// set up the moving averages
sma = new SMA(spread_series, SMALength);
sma.Color = Color.Yellow;
Draw(sma, 2);
// set up bollinger bands
bbu = new BBU(spread_series, SMALength, BBUOrder);
bbu.Color = Color.Green;
bbl = new BBL(spread_series, SMALength, BBLOrder);
bbl.Color = Color.Green;
Draw(bbu, 2);
Draw(bbl, 2);
Draw(spread_series, 2);
}
public override void OnBarSlice(long size)
{
if (Instrument == CSCO)
{
double spread = CSCO.Bar.Close / DELL.Bar.Close;
spread_series.Add(CSCO.Bar.DateTime, spread);
if (bbl.Count == 0)
return;
if (!HasPosition)
{
if (spread < bbl.Last)
{
Buy(CSCO, Qty);
Sell(DELL, Qty);
}
}
else
{
if (spread > bbu.Last)
{
Sell(CSCO, Qty);
Buy(DELL, Qty);
}
}
}
}
}