#region Namespaces using System; using System.IO; using System.Linq; using System.Collections.Generic; #endregion namespace ScriptCode { /// <summary> /// Multi-symbol trading strategy scripts are used for simultaneously trading a group of symbols from a single strategy instance. /// </summary> public partial class MyMultiSymbolTradingStrategy : MultiSymbolTradingStrategyScriptBase // NEVER CHANGE THE CLASS NAME { #region Variables // Use for holding user specified signals indexed by symbol index. private Signal[] _sortSignal; // Use for the number of symbols to hold. private int _holdSymbols; // Use for the number of bars to hold the selected symbols. private int _holdBars; // Use for counting the number of bars the current open positions have been held. private int _heldBars; // Use for holding the symbol signal values <symbol index, latest signal value for symbol>. private List<Tuple<int, double>> _symbolSignals; // Use for indicating whether the strategy is currently in sell mode or buy mode. private bool _isSellMode; #endregion #region OnInitialize /// <summary> /// This function is used for accepting the script parameters and for initializing the script prior to all other function calls. /// Once the script is assigned to a desktop, its parameter values can be specified by the user and can be selected for optimization. /// </summary> /// -------------------------------------------------------------------------------------------------- /// PLEASE USE THE SCRIPT WIZARD (CTRL+W) TO ADD, EDIT AND REMOVE THE SCRIPT PARAMETERS /// -------------------------------------------------------------------------------------------------- /// YOU MUST SET A PARAM TAG FOR EACH PARAMETER ACCEPTED BY THIS FUNCTION. /// ALL PARAM TAGS SHOULD BE SET IN THE 'OnInitialize' REGION, RIGHT ABOVE THE 'OnInitialize' FUNCTION. /// THE ORDER OF THE TAGS MUST MATCH THE ORDER OF THE ACTUAL PARAMETERS. /// REQUIRED ATTRIBUTES: /// (1) name: The exact parameter name. /// (2) type: The type of data to collect from the user: /// Set to "Integer" when the data type is 'int' /// Set to "IntegerArray" when the data type is 'int[]' /// Set to "DateTime" when the data type is 'long' /// Set to "DateTimeArray" when the data type is 'long[]' /// Set to "Boolean" when the data type is 'bool' /// Set to "BooleanArray" when the data type is 'bool[]' /// Set to "Double" when the data type is 'double' /// Set to "DoubleArray" when the data type is 'double[]' /// Set to "String" when the data type is 'string' /// Set to "StringArray" when the data type is 'string[]' /// Set to "Indicator" when the data type is 'Indicator' /// Set to "Pattern" when the data type is 'Pattern' /// Set to "Signal" when the data type is 'Signal' /// Set to "Drawing" when the data type is 'Drawing' /// OPTIONAL ATTRIBUTES: /// (3) default: The default parameter value is only valid when the type is Integer, Boolean, Double, String or an API Type. /// (4) min: The minimum parameter value is only valid when the type is Integer or Double. /// (5) max: The maximum parameter value is only valid when the type is Integer or Double. /// EXAMPLE: <param name="" type="" default="" min="" max="">Enter the parameter description here.</param> /// -------------------------------------------------------------------------------------------------- /// <param name="sortSignal" type="Signal" default="" min="" max="">The signal to use for sorting the symbols.</param> /// <param name="holdSymbols" type="Integer" default="10" min="1" max="10000">The number of symbols to hold.</param> /// <param name="holdBars" type="Integer" default="30" min="1" max="10000000">The number of bars to hold the selected symbols.</param> public void OnInitialize( Signal sortSignal, int holdSymbols, int holdBars) { // Create an array large enough to hold a single signal for each symbol. _sortSignal = new Signal[SymbolCount()]; // Iterate over all of the symbol indexes. for (int symbolIndexItem = 0; symbolIndexItem < _sortSignal.Length; symbolIndexItem++) { // Create a copy for the current symbol index. _sortSignal[symbolIndexItem] = SignalSetSymbol(sortSignal, symbolIndexItem); // Plot the signal on the symbol's chart. ChartSignalPlot(symbolIndexItem, _sortSignal[symbolIndexItem], "", - 1, 1); } // Set the script parameter to a variable. _holdSymbols = holdSymbols; // Set the script parameter to a variable. _holdBars = holdBars; // Create for holding the symbol signal values <symbol index, latest signal value for symbol>. _symbolSignals = new List<Tuple<int, double>>(); } #endregion #region OnBarUpdate /// <summary> /// This function is called after each new bar of each symbol assigned to the desktop strategy. /// It should evaluate the specified symbol and its new bar in order to determine whether to generate new orders for it. /// Never create indicators, signals or patterns from OnBarUpdate, for performance reasons those should be created from OnInitialize. /// </summary> /// <param name="symbolIndex" type="Integer">The index of the symbol in the strategy symbol table</param> /// <param name="dataSeries" type="Integer">The number indicating the data series from which the symbol was updated. /// According to the desktop strategy data series settings: 0 for the main data series, 1 or 2 for the second and third, respectively</param> /// <param name="isLastSymbol" type="Boolean">Indicates whether this is the last symbol to be updated for the current bar. /// The parameter is valid when the bars for different symbols have matching timestamps, e.g. 1m, 5m, 1d, 1w, etc.</param> public override void OnBarUpdate( int symbolIndex, int dataSeries, bool isLastSymbol) { // Check whether all of the symbols have been updated. if (isLastSymbol) { // Check whether the strategy is in sell mode. if (_isSellMode) { // Increase the number of held bars. _heldBars++; // Check whether the number of held bars matches the specified number of hold bars. if (_heldBars == _holdBars) { // Get the open position indexes for all of the symbols. int[] openPositionIndexes = PositionByStatus(IQ_TradeStatus.OPEN); // Iterate over the open positions for all of the symbols while closing them one by one. for (int i = 0; i < openPositionIndexes.Length; i++) { // Buy to cover the current symbol. BrokerMarket(IQ_ActionType.BUY_TO_COVER, PositionSymbolIndex(openPositionIndexes[i]), PositionCurrentQuantity(openPositionIndexes[i]), IQ_TIF.DAY, ""); } // Clear the number of held bars. _heldBars = 0; // Set to indicate that the strategy is currently is buy mode. _isSellMode = false; } } // The strategy is in buy mode. else { // Clear the list of signals. _symbolSignals.Clear(); // Iterate over the symbols. for (int symIndex = 0; symIndex < SymbolCount(); symIndex++) { // Get the signal value for the latest bar of the current symbol. _symbolSignals.Add(new Tuple<int, double>(symIndex, _sortSignal[symIndex][0])); } // Sort the symbols by descending signal values so that those with the higher signal values come first. _symbolSignals.Sort((x, y) => y.Item2.CompareTo(x.Item2)); // Iterate over the number of symbols to hold. for (int i = 0; i < _symbolSignals.Count && i < _holdSymbols; i++) { // Short the current symbol while assuming that a position sizing script will assign the quantity. BrokerMarket(IQ_ActionType.SELL_SHORT, _symbolSignals[i].Item1, 0, IQ_TIF.DAY, ""); } // Set to indicate that the strategy is currently is sell mode. _isSellMode = true; } } } #endregion #region OnOrderUpdate /// <summary> /// This function is called when an order is executed or cancelled. /// </summary> /// <param name="symbolIndex" type="Integer">The symbol index</param> /// <param name="orderIndex" type="Integer">The order index</param> /// <param name="status" type="IQ_Status">The updated status of the order</param> public override void OnOrderUpdate( int symbolIndex, int orderIndex, IQ_Status status) { // OnOrderUpdate Content } #endregion #region OnTradeUpdate /// <summary> /// This function is called when a trade is opened or closed. /// </summary> /// <param name="symbolIndex" type="Integer">The symbol index</param> /// <param name="tradeIndex" type="Integer">The trade index</param> /// <param name="status" type="IQ_TradeStatus">The updated status of the trade</param> public override void OnTradeUpdate( int symbolIndex, int tradeIndex, IQ_TradeStatus status) { // OnTradeUpdate Content } #endregion #region OnPositionUpdate /// <summary> /// This function is called when a position is opened or closed. /// </summary> /// <param name="symbolIndex" type="Integer">The symbol index</param> /// <param name="positionIndex" type="Integer">The position index</param> /// <param name="status" type="IQ_TradeStatus">The updated status of the position</param> public override void OnPositionUpdate( int symbolIndex, int positionIndex, IQ_TradeStatus status) { // OnPositionUpdate Content } #endregion #region OnNewsUpdate /// <summary> /// This function is called when a news update is received and only if the NO_NEWS_UPDATES comment is removed. /// </summary> /// <param name="symbolIndex" type="Integer">The symbol index for the update</param> /// <param name="dateTime" type="DateTime">The date/time in which the update was received by the platform</param> /// <param name="title" type="String">The update title</param> /// <param name="message" type="String">The update message</param> /// <param name="type" type="IQ_MessageType">The message type</param> public override void OnNewsUpdate( int symbolIndex, long dateTime, string title, string message, IQ_MessageType type) { // OnNewsUpdate Content // [NO_NEWS_UPDATES] - Delete this comment to enable news updates to this strategy. } #endregion #region OnRSSUpdate /// <summary> /// This function is called when an RSS update is received and only if the NO_RSS_UPDATES comment is removed. /// </summary> /// <param name="symbolIndex" type="Integer">The symbol index for the update</param> /// <param name="dateTime" type="DateTime">The date/time in which the update was received by the platform</param> /// <param name="title" type="String">The update title</param> /// <param name="message" type="String">The update message</param> /// <param name="type" type="IQ_MessageType">The message type</param> public override void OnRSSUpdate( int symbolIndex, long dateTime, string title, string message, IQ_MessageType type) { // OnRSSUpdate Content // [NO_RSS_UPDATES] - Delete this comment to enable RSS updates to this strategy. } #endregion #region OnAlertUpdate /// <summary> /// This function is called when an alert update is received and only if the NO_ALERT_UPDATES comment is removed. /// </summary> /// <param name="symbolIndex" type="Integer">The symbol index for the update</param> /// <param name="dateTime" type="DateTime">The date/time in which the update was received by the platform</param> /// <param name="message" type="String">The update message</param> /// <param name="type" type="IQ_MessageType">The message type</param> public override void OnAlertUpdate( int symbolIndex, long dateTime, string message, IQ_MessageType type) { // OnAlertUpdate Content // [NO_ALERT_UPDATES] - Delete this comment to enable alert updates to this strategy. } #endregion #region OnJournalUpdate /// <summary> /// This function is called when a journal update is received and only if the NO_JOURNAL_UPDATES comment is removed. /// </summary> /// <param name="symbolIndex" type="Integer">The symbol index for the update</param> /// <param name="dateTime" type="DateTime">The date/time in which the update was received by the platform</param> /// <param name="title" type="String">The update title</param> /// <param name="message" type="String">The update message</param> /// <param name="type" type="IQ_MessageType">The message type</param> public override void OnJournalUpdate( int symbolIndex, long dateTime, string title, string message, IQ_MessageType type) { // OnJournalUpdate Content // [NO_JOURNAL_UPDATES] - Delete this comment to enable journal updates to this strategy. } #endregion #region OnDataConnectionUpdate /// <summary> /// This function is called when a data connection update is received and only if the NO_DATA_CONNECTION_UPDATES comment is removed. /// </summary> /// <param name="symbolIndex" type="Integer">The symbol index for the update</param> /// <param name="dateTime" type="DateTime">The date/time in which the update was received by the platform</param> /// <param name="message" type="String">The update message</param> /// <param name="type" type="IQ_MessageType">The message type</param> public override void OnDataConnectionUpdate( int symbolIndex, long dateTime, string message, IQ_MessageType type) { // OnDataConnectionUpdate Content // [NO_DATA_CONNECTION_UPDATES] - Delete this comment to enable data connection updates to this strategy. } #endregion #region OnBrokerConnectionUpdate /// <summary> /// This function is called when a broker connection update is received and only if the NO_BROKER_CONNECTION_UPDATES comment is removed. /// </summary> /// <param name="dateTime" type="DateTime">The date/time in which the update was received by the platform</param> /// <param name="message" type="String">The update message</param> /// <param name="type" type="IQ_MessageType">The message type</param> public override void OnBrokerConnectionUpdate( long dateTime, string message, IQ_MessageType type) { // OnBrokerConnectionUpdate Content // [NO_BROKER_CONNECTION_UPDATES] - Delete this comment to enable broker connection updates to this strategy. } #endregion #region OnShutdown /// <summary> /// This function is called when the script is shutdown. /// </summary> public override void OnShutdown() { // OnShutdown Content } #endregion } }

The Algorithmic Trading Software for Hedge Funds and Quants