Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Addition of Interactive Brokers Algorithmic orders #1203

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion Algorithm.CSharp/BasicTemplateAlgorithm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
*/

using QuantConnect.Data;
using System.Collections.Generic;
using QuantConnect.Orders;

namespace QuantConnect.Algorithm.CSharp
{
Expand Down Expand Up @@ -55,7 +57,11 @@ public override void OnData(Slice data)
{
if (!Portfolio.Invested)
{
SetHoldings(_spy, 1);
//SetHoldings(_spy, 1);
List<AlgoParams> AlgoParams = new List<AlgoParams>();
AlgoParams.Add(new AlgoParams("adaptivePriority", "Normal"));
SetHoldings(_spy, 1, false, "", OrderAlgorithm.AdaptiveAlgo, AlgoParams);
//MarketOrder(_spy, 100, true, "", OrderAlgorithm.AdaptiveAlgo, AlgoParams);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert changes to this file.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will do, this wasn't supposed to be committed.

Debug("Purchased Stock");
}
}
Expand Down
62 changes: 41 additions & 21 deletions Algorithm/QCAlgorithm.Trading.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,12 @@ public OrderTicket Order(Symbol symbol, decimal quantity)
/// <param name="quantity">Number of shares to request.</param>
/// <param name="asynchronous">Send the order asynchrously (false). Otherwise we'll block until it fills</param>
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <seealso cref="MarketOrder(Symbol, decimal, bool, string)"/>
public OrderTicket Order(Symbol symbol, decimal quantity, bool asynchronous = false, string tag = "")
/// <param name="algorithm">Interactive Brokers algorithm to trade with</param>
/// <param name="algoparams">Parameters for an Interactive Brokers Algorithm order</param>
/// <seealso cref="MarketOrder(QuantConnect.Symbol, decimal, bool, string, OrderAlgorithm, List{AlgoParams})/>"/>
public OrderTicket Order(Symbol symbol, decimal quantity, bool asynchronous = false, string tag = "", OrderAlgorithm algorithm = OrderAlgorithm.None, List<AlgoParams> algoparams = null)
{
return MarketOrder(symbol, quantity, asynchronous, tag);
return MarketOrder(symbol, quantity, asynchronous, tag, algorithm, algoparams);
}

/// <summary>
Expand All @@ -168,10 +170,12 @@ public OrderTicket Order(Symbol symbol, decimal quantity, bool asynchronous = fa
/// <param name="quantity">Number of shares to request.</param>
/// <param name="asynchronous">Send the order asynchrously (false). Otherwise we'll block until it fills</param>
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <param name="algorithm">Interactive Brokers algorithm to trade with</param>
/// <param name="algoparams">Parameters for an Interactive Brokers Algorithm order</param>
/// <returns>int Order id</returns>
public OrderTicket MarketOrder(Symbol symbol, int quantity, bool asynchronous = false, string tag = "")
public OrderTicket MarketOrder(Symbol symbol, int quantity, bool asynchronous = false, string tag = "", OrderAlgorithm algorithm = OrderAlgorithm.None, List<AlgoParams> algoparams = null)
{
return MarketOrder(symbol, (decimal)quantity, asynchronous, tag);
return MarketOrder(symbol, (decimal)quantity, asynchronous, tag, algorithm, algoparams);
}

/// <summary>
Expand All @@ -181,10 +185,12 @@ public OrderTicket MarketOrder(Symbol symbol, int quantity, bool asynchronous =
/// <param name="quantity">Number of shares to request.</param>
/// <param name="asynchronous">Send the order asynchrously (false). Otherwise we'll block until it fills</param>
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <param name="algorithm">Interactive Brokers algorithm to trade with</param>
/// <param name="algoparams">Parameters for an Interactive Brokers Algorithm order</param>
/// <returns>int Order id</returns>
public OrderTicket MarketOrder(Symbol symbol, double quantity, bool asynchronous = false, string tag = "")
public OrderTicket MarketOrder(Symbol symbol, double quantity, bool asynchronous = false, string tag = "", OrderAlgorithm algorithm = OrderAlgorithm.None, List<AlgoParams> algoparams = null)
{
return MarketOrder(symbol, (decimal)quantity, asynchronous, tag);
return MarketOrder(symbol, (decimal)quantity, asynchronous, tag, algorithm, algoparams);
}

/// <summary>
Expand All @@ -194,8 +200,10 @@ public OrderTicket MarketOrder(Symbol symbol, double quantity, bool asynchronous
/// <param name="quantity">Number of shares to request.</param>
/// <param name="asynchronous">Send the order asynchrously (false). Otherwise we'll block until it fills</param>
/// <param name="tag">Place a custom order property or tag (e.g. indicator data).</param>
/// <param name="algorithm">Interactive Brokers algorithm to trade with</param>
/// <param name="algoparams">Parameters for an Interactive Brokers Algorithm order</param>
/// <returns>int Order id</returns>
public OrderTicket MarketOrder(Symbol symbol, decimal quantity, bool asynchronous = false, string tag = "")
public OrderTicket MarketOrder(Symbol symbol, decimal quantity, bool asynchronous = false, string tag = "", OrderAlgorithm algorithm = OrderAlgorithm.None, List<AlgoParams> algoparams = null)
{
var security = Securities[symbol];

Expand All @@ -212,7 +220,7 @@ public OrderTicket MarketOrder(Symbol symbol, decimal quantity, bool asynchronou
return mooTicket;
}

var request = CreateSubmitOrderRequest(OrderType.Market, security, quantity, tag);
var request = CreateSubmitOrderRequest(OrderType.Market, security, quantity, tag, 0, 0, algorithm, algoparams);

// If warming up, do not submit
if (IsWarmingUp)
Expand Down Expand Up @@ -725,7 +733,7 @@ private OrderResponse PreOrderChecksImpl(SubmitOrderRequest request)

if (security.Holdings.IsShort)
return OrderResponse.Error(request, OrderResponseErrorCode.UnsupportedRequestType, "The security with symbol '" + request.Symbol.ToString() + "' has a short option position. Only long option positions are exercisable.");

if (request.Quantity > security.Holdings.Quantity)
return OrderResponse.Error(request, OrderResponseErrorCode.UnsupportedRequestType, "Cannot exercise more contracts of '" + request.Symbol.ToString() + "' than is currently available in the portfolio. ");

Expand Down Expand Up @@ -832,10 +840,13 @@ public void SetMaximumOrders(int max)
/// <param name="symbol">string symbol we wish to hold</param>
/// <param name="percentage">double percentage of holdings desired</param>
/// <param name="liquidateExistingHoldings">liquidate existing holdings if neccessary to hold this stock</param>
/// <param name="tag">Tag the order with a short string.</param>
/// <param name="algorithm">Interactive Brokers algorithm to trade with</param>
/// <param name="algoparams">Parameters for an Interactive Brokers Algorithm order</param>
/// <seealso cref="MarketOrder"/>
public void SetHoldings(Symbol symbol, double percentage, bool liquidateExistingHoldings = false)
public void SetHoldings(Symbol symbol, double percentage, bool liquidateExistingHoldings = false, string tag = "", OrderAlgorithm algorithm = OrderAlgorithm.None, List<AlgoParams> algoparams = null)
{
SetHoldings(symbol, (decimal)percentage, liquidateExistingHoldings);
SetHoldings(symbol, (decimal)percentage, liquidateExistingHoldings, tag, algorithm, algoparams);
}

/// <summary>
Expand All @@ -845,10 +856,12 @@ public void SetHoldings(Symbol symbol, double percentage, bool liquidateExisting
/// <param name="percentage">float percentage of holdings desired</param>
/// <param name="liquidateExistingHoldings">bool liquidate existing holdings if neccessary to hold this stock</param>
/// <param name="tag">Tag the order with a short string.</param>
/// <param name="algorithm">Interactive Brokers algorithm to trade with</param>
/// <param name="algoparams">Parameters for an Interactive Brokers Algorithm order</param>
/// <seealso cref="MarketOrder"/>
public void SetHoldings(Symbol symbol, float percentage, bool liquidateExistingHoldings = false, string tag = "")
public void SetHoldings(Symbol symbol, float percentage, bool liquidateExistingHoldings = false, string tag = "", OrderAlgorithm algorithm = OrderAlgorithm.None, List<AlgoParams> algoparams = null)
{
SetHoldings(symbol, (decimal)percentage, liquidateExistingHoldings, tag);
SetHoldings(symbol, (decimal)percentage, liquidateExistingHoldings, tag, algorithm, algoparams);
}

/// <summary>
Expand All @@ -858,10 +871,12 @@ public void SetHoldings(Symbol symbol, float percentage, bool liquidateExistingH
/// <param name="percentage">float percentage of holdings desired</param>
/// <param name="liquidateExistingHoldings">bool liquidate existing holdings if neccessary to hold this stock</param>
/// <param name="tag">Tag the order with a short string.</param>
/// <param name="algorithm">Interactive Brokers algorithm to trade with</param>
/// <param name="algoparams">Parameters for an Interactive Brokers Algorithm order</param>
/// <seealso cref="MarketOrder"/>
public void SetHoldings(Symbol symbol, int percentage, bool liquidateExistingHoldings = false, string tag = "")
public void SetHoldings(Symbol symbol, int percentage, bool liquidateExistingHoldings = false, string tag = "", OrderAlgorithm algorithm = OrderAlgorithm.None, List<AlgoParams> algoparams = null)
{
SetHoldings(symbol, (decimal)percentage, liquidateExistingHoldings, tag);
SetHoldings(symbol, (decimal)percentage, liquidateExistingHoldings, tag, algorithm, algoparams);
}

/// <summary>
Expand All @@ -873,8 +888,10 @@ public void SetHoldings(Symbol symbol, int percentage, bool liquidateExistingHol
/// <param name="percentage">decimal fraction of portfolio to set stock</param>
/// <param name="liquidateExistingHoldings">bool flag to clean all existing holdings before setting new faction.</param>
/// <param name="tag">Tag the order with a short string.</param>
/// <param name="algorithm">Interactive Brokers algorithm to trade with</param>
/// <param name="algoparams">Parameters for an Interactive Brokers Algorithm order</param>
/// <seealso cref="MarketOrder"/>
public void SetHoldings(Symbol symbol, decimal percentage, bool liquidateExistingHoldings = false, string tag = "")
public void SetHoldings(Symbol symbol, decimal percentage, bool liquidateExistingHoldings = false, string tag = "", OrderAlgorithm algorithm = OrderAlgorithm.None, List<AlgoParams> algoparams = null)
{
//Initialize Requirements:
Security security;
Expand All @@ -894,7 +911,8 @@ public void SetHoldings(Symbol symbol, decimal percentage, bool liquidateExistin
if (holdingSymbol != symbol && holdings.AbsoluteQuantity > 0)
{
//Go through all existing holdings [synchronously], market order the inverse quantity:
Order(holdingSymbol, -holdings.Quantity, false, tag);
//May take a long time synchronously if using an algorithm, food for thought
Order(holdingSymbol, -holdings.Quantity, false, tag, algorithm, algoparams);
}
}
}
Expand All @@ -903,7 +921,8 @@ public void SetHoldings(Symbol symbol, decimal percentage, bool liquidateExistin
var quantity = CalculateOrderQuantity(symbol, percentage);
if (Math.Abs(quantity) > 0)
{
MarketOrder(symbol, quantity, false, tag);
//May take a long time synchronously if using an algorithm, food for thought
MarketOrder(symbol, quantity, false, tag, algorithm, algoparams);
}
}

Expand Down Expand Up @@ -1060,9 +1079,10 @@ public bool IsMarketOpen(Symbol symbol)
return exchangeHours.IsOpen(time, false);
}

private SubmitOrderRequest CreateSubmitOrderRequest(OrderType orderType, Security security, decimal quantity, string tag, decimal stopPrice = 0m, decimal limitPrice = 0m)
private SubmitOrderRequest CreateSubmitOrderRequest(OrderType orderType, Security security, decimal quantity, string tag, decimal stopPrice = 0m, decimal limitPrice = 0m, OrderAlgorithm algorithm = OrderAlgorithm.None, List<AlgoParams> algoparams = null)
{
return new SubmitOrderRequest(orderType, security.Type, security.Symbol, quantity, stopPrice, limitPrice, UtcTime, tag);
return new SubmitOrderRequest(orderType, security.Type, security.Symbol, quantity, stopPrice, limitPrice, UtcTime, tag, algorithm, algoparams);
}

}
}
64 changes: 61 additions & 3 deletions Brokerages/InteractiveBrokers/InteractiveBrokersBrokerage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1466,6 +1466,61 @@ private void HandlePortfolioUpdates(object sender, IB.UpdatePortfolioEventArgs e
_accountHoldings[holding.Symbol.Value] = holding;
}

/// <summary>
/// Convert OrderAlgorithm setting into respective string to be used for Interactive Brokers order API
/// </summary>
private string ConvertOrderAlgorithm(OrderAlgorithm algorithm)
{
switch (algorithm)
{
case OrderAlgorithm.None:
return null;
case OrderAlgorithm.AdaptiveAlgo:
return "AdaptiveAlgo";
case OrderAlgorithm.ArrivalPrice:
return "ArrivalPx";
case OrderAlgorithm.ClosePrice:
return "ClosePx";
case OrderAlgorithm.DarkIce:
return "DarkIce";
case OrderAlgorithm.AccumulateDistribute:
return "AD";
case OrderAlgorithm.PercentageOfVolume:
return "PctVol";
case OrderAlgorithm.TWAP:
return "Twap";
case OrderAlgorithm.PriceVariantPercentageOfVolumeStrategy:
return "PctVolPx";
case OrderAlgorithm.SizeVariantPercentageOfVolumeStrategy:
return "PctVolSz";
case OrderAlgorithm.TimeVariantPercentageOfVolumeStrategy:
return "PctVolTm";
case OrderAlgorithm.VWAP:
return "Vwap";
case OrderAlgorithm.BalanceImpactRisk:
return "BalanceImpactRisk";
case OrderAlgorithm.MinimiseImpact:
return "MinimiseImpact";
}
return null;
}

/// <summary>
/// Converts an AlgoParams List to a TagValue list to be used in Interactive Brokers order API
/// </summary>
/// <remarks>
/// Is there a better way to do this?
/// </remarks>
private List<TagValue> ConvertAlgoParams(List<AlgoParams> algoparams)
{
List<TagValue> output = new List<TagValue>();
foreach (AlgoParams n in algoparams)
{
output.Add(new TagValue(n.Tag, n.Value));
}
return output;
}

/// <summary>
/// Converts a QC order to an IB order
/// </summary>
Expand All @@ -1482,17 +1537,20 @@ private IBApi.Order ConvertOrder(Order order, Contract contract, int ibOrderId)
AllOrNone = false,
Tif = IB.TimeInForce.GoodTillCancel,
Transmit = true,
Rule80A = _agentDescription
};
Rule80A = _agentDescription,
AlgoStrategy = ConvertOrderAlgorithm(order.Algorithm),
AlgoParams = ConvertAlgoParams(order.AlgoParams)
};

if (order.Type == OrderType.MarketOnOpen)
{
ibOrder.Tif = IB.TimeInForce.MarketOnOpen;
}

var limitOrder = order as LimitOrder;
var stopMarketOrder = order as StopMarketOrder;
var stopLimitOrder = order as StopLimitOrder;

if (limitOrder != null)
{
ibOrder.LmtPrice = Convert.ToDouble(RoundPrice(limitOrder.LimitPrice, GetMinTick(contract)));
Expand Down
7 changes: 5 additions & 2 deletions Common/Orders/LimitOrder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

using System;
using QuantConnect.Securities;
using System.Collections.Generic;

namespace QuantConnect.Orders
{
Expand Down Expand Up @@ -51,8 +52,10 @@ public LimitOrder()
/// <param name="time">Time the order was placed</param>
/// <param name="limitPrice">Price the order should be filled at if a limit order</param>
/// <param name="tag">User defined data tag for this order</param>
public LimitOrder(Symbol symbol, decimal quantity, decimal limitPrice, DateTime time, string tag = "")
: base(symbol, quantity, time, tag)
/// <param name="algorithm">Interactive Brokers algorithm to trade with</param>
/// <param name="algoparams">Parameters for an Interactive Brokers Algorithm order</param>
public LimitOrder(Symbol symbol, decimal quantity, decimal limitPrice, DateTime time, string tag = "", OrderAlgorithm algorithm = OrderAlgorithm.None, List<AlgoParams> algoparams = null)
: base(symbol, quantity, time, tag, algorithm, algoparams)
{
LimitPrice = limitPrice;

Expand Down
7 changes: 5 additions & 2 deletions Common/Orders/MarketOrder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

using System;
using QuantConnect.Securities;
using System.Collections.Generic;

namespace QuantConnect.Orders
{
Expand Down Expand Up @@ -45,8 +46,10 @@ public override OrderType Type
/// <param name="quantity">Quantity of the asset we're seeking to trade</param>
/// <param name="time">Time the order was placed</param>
/// <param name="tag">User defined data tag for this order</param>
public MarketOrder(Symbol symbol, decimal quantity, DateTime time, string tag = "")
: base(symbol, quantity, time, tag)
/// <param name="algorithm">Interactive Brokers algorithm to trade with</param>
/// <param name="algoparams">Parameters for an Interactive Brokers Algorithm order</param>
public MarketOrder(Symbol symbol, decimal quantity, DateTime time, string tag = "", OrderAlgorithm algorithm = OrderAlgorithm.None, List<AlgoParams> algoparams = null)
: base(symbol, quantity, time, tag, algorithm, algoparams)
{
}

Expand Down
Loading