Archive for the 'C#' Category

9.4.0.9 Bugfix and Cleanup Release

This release includes some bugfixes and some cleanup. I had realized that some residual console code was left in the response to the historical request function, and that the java framework from IB’s method of calling the OnHistResponse method with null parameters to terminate the historical response was just plain wrong. I added two properties to the HistoricalResponse Event Arguments that allow you to determine where you are in the response, and you know you are done when RecordNumber == RecordCount-1. Additionally I cleaned up the RequestExecutions function with some issues relating to the filter, and made all of the eventarguments serializable. Below are the full release notes:

9.4.0.9 Bug Fix and Clean up - 2/10/08

  • Made all EventArgs Serializable as well as the new enumeration FATypes.
  • Fixed bug in OrderType.MarketOnClose - changed Description from "MKTCLS" to "MOC"
  • Fixed RequestExecution method to allow you to pass a null or empty filter to get all executions.
  • Changed HistoricalRequest Response. Added two parameters to the event args that lets the user know how far the download is. Also no longer calls function after download completed with null entries, since you can determine that the call is complete by the Record Number / Record Count properties.
  • Made EnumDescConverter Static, as all methods were static.

As usual, download it from the utilities page here, or directly here.

9.4.0.8 Cleanup Release

Hello everyone, these last releases have been pretty rapid fire. This release does not change any functionality, and is strictly the result of me running FxCop over the code again. I now use Visual Studio 2008 and their Code Analysis Engine is an integrated form of FxCop. In any case it caught a lot of embarrassing spelling and abbreviation mistakes amongst other things. The most common changes are listed below.

Please note this release has breaking changes, not to functionality, but you will have to update your events and function calls to the correctly spelled equivalents.

  • 9.4.0.8 Code Clean up - 1/31/08
    • Ran Vs2008 Code Analysis Wizard / FxCop and implemented cleanup
      • Numerous Spelling Changes
        • All Mkt references went to Market
        • All Req references went to Request etc.
        • All Lmt references went to Limit
        • All Indice references went to index
      • Added a lot of CultureInfo related fixes, making sure to provide invarient parsing
    • Fixed VB Client, used old contracts, and changed contract references to equity/future

As always, please go to the utility page here to get the latest release, or directly from here.

9.4.0.7 Bug Fix Release

So we have quite the community of bug reporting users, and I have created a new release which closes all outstanding issues. This is still against the IB 9.40 release, for the first time in about a year IB actually moved the latest beta release to stable, without a new API release.

The following is the change log from the release notes

  • 9.4.0.7 Bug Fix Release - 1/26/08
    • Changed FAMethod to Enumeration
    • Changed OrderState.Status to enumeration
    • Fixed several data parsing problems related to empty strings
    • Added Visual Studio 2008 solution, all files are still C# 2.0 compliant.

As I mentioned above, I now develop in Visual Studio 2008 against .net 3.5, but have been careful to keep this library C# 2.0 compliant. Let me know what platform you are using, if everyone has switched to .net 3.5, I may consider using new feature in future releases.

Without further ado, goto the utilities page to download the latest version or download directly from here.

9.4.0.6 IB API Release

Hello Everyone, it sure has been some time since I’ve posted. I have been actively developing various ATS strategies, and have revised the C# Interactive Brokers API library to support the 9.40 beta currently out from IB. I have also fixed all known bugs as reported via email or through the forums. The following is the change log from the release notes.

  • 9.4.0.6 API and Bug Fix Release - 12/9/07
    • Updated to support 9.40 Interactive Brokers API Release
      • What-If Order Support
      • Commission Data
      • Contract/Contract Details Refactored
    • Fixed Historical Request 1 day limitation
    • Changed TickSizeEvent Args to use TickType instead of TickerType
    • All Enums / Container classes are now marked serializable
    • Fixed bug on Stop Limit Orders "STPLMT" -> "STP LMT"

As always please post on the with any questions.

Please precede to download from the utilities page, or directly here.

Average Directional Movement Index ADX Formula in C#

So in my continuing series of C# implementations of common indicators, I spent all of yesterday working out the ADX. The ADX was originally developed by J. Welles Wilder and published in his book New Concepts in Technical Trading Systems, June 1978.

Various sites report implementations, but always define it in terms of indicators which have varying definitions. Namely FxStreet defines the general concept here, but only in terms of DI+/-, TR and DM+/-, each of which has varying definitions. ForexReal defines ADX here, but uses a completely different concept of TR. Stockwiz has a good overview of all of the variables used (at least they define all of their variables) here. I will be defining the ADX all the way down to price action (what you need when you are coding this…) as best I can to the original definition by J Welles Wilder.

Lets start by defining the Directional Move indicators

Directional Move Indicator

         = the Positive Direction Movement Indicator

          = the Negative Direction Movement Indicator

We use two helper variables to track the delta extreme price changes from yesterday

If today’s range is entirely within yesterday’s range, or the range is the same, then there has been no directional movement.

If the range moved up, then there has been a positive directional move.

If the range moved down, then there has been a negative directional move.

Average Directional Move Indicator

          = the Average Positive Direction Movement Indicator for N periods

          = the Average Negative Direction Movement Indicator for N periods

The Welles Wilder Average is used here to stay true to form, but this average introduces a lot of latency, so I will also implement an exponential moving average.

Alternatively, the formula for the ADM with an exponential moving average is shown below.

True Range

          is the true range for a given period. It is a measure of volatility and takes into account any overnight gap in the period’s price.

Average True Range

          is the average true range for N periods.

The Welles Wilder Average is used here again to stay true to form, but for my C# implementation I will be using the exponential moving average.

Alternatively the ATR can be calculated with the exponential moving average as shown below.

Directional Index

          is the average positive directional movement indicator normalized by the average true range.

          is the average negative directional movement indicator normalized by the average true range.

The directional index calculation is very straight forward and shown below.

Directional Movement Index

          - the directional movement index is the difference of the directional indices over the sum directional indices.

Average Directional Movement Index

          is the average directional movement calculated over N periods.

Staying true to form again, the Welles Wilder Average is used below.

Again, you can alternatively use the exponential moving average as shown below.

C# implementation

So after the laborious research to determine exactly what the ADX is and should be (exponential vs Welles Wilder Average), here is the C# implementation of this indicator.

    //The Average Directional Indicator

    if(barHistory[timePeriod].Count > 1)

    {

        //Directional Movement Indicator

        double deltaHigh = cBar.High - barHistory[timePeriod][barHistory[timePeriod].Count - 2].High;

        double deltaLow = barHistory[timePeriod][barHistory[timePeriod].Count - 2].Low - cBar.Low;

        if((deltaHigh < 0 && deltaLow < 0) || (deltaHigh == deltaLow))

        {

            sig.DmPlus = 0;

            sig.DmMinus = 0;

        }

        else
if(deltaHigh > deltaLow)

        {

            sig.DmPlus = deltaHigh;

            sig.DmMinus = 0;

        }

        else
if (deltaHigh < deltaLow)

        {

            sig.DmPlus = 0;

            sig.DmMinus = deltaLow;

        }

 
 

        //Average Directional Movement Indicator

        if(barHistory[timePeriod].Count <= 2)

        {

            sig.AdmPlus = sig.DmPlus;

            sig.AdmMinus = sig.DmMinus;

        }

        else

        {

            double a = (double) 2/(double) (calc.DMIPeriod + 1);

            sig.AdmPlus = sig.DmPlus * a +

                symbolHistory[timePeriod][symbolHistory[timePeriod].Count-2].AdmPlus * (1-a);

            sig.AdmMinus = sig.DmMinus * a +

                symbolHistory[timePeriod][symbolHistory[timePeriod].Count - 2].AdmMinus * (1 - a);

        }

 
 

        //True Range Indicator

        sig.TrueRange = Math.Max(Math.Abs(cBar.High - cBar.Low),

                                 Math.Max(

                                     Math.Abs(cBar.High - barHistory[timePeriod][barHistory[timePeriod].Count - 2].Close),

                                     Math.Abs(barHistory[timePeriod][barHistory[timePeriod].Count - 2].Close - cBar.Low)));

 
 

        //Average True Range Indicator

        if(barHistory[timePeriod].Count <= 2)

        {

            sig.AverageTrueRange = sig.TrueRange;

        }

        else

        {

            double a = (double)2 / (double)(calc.ADXPeriod + 1);

            sig.AverageTrueRange = sig.TrueRange * a +

                symbolHistory[timePeriod][symbolHistory[timePeriod].Count - 2].AverageTrueRange * (1 - a);

        }

 
 

        //Directional index Indicator

        if (sig.TrueRange != 0)

        {

            sig.DiPlus = 100 * sig.AdmPlus/sig.TrueRange;

            sig.DiMinus = 100 * sig.AdmMinus/sig.TrueRange;

        }

        else

        {

            sig.DiPlus = symbolHistory[timePeriod][symbolHistory[timePeriod].Count - 2].DiPlus;

            sig.DiMinus = symbolHistory[timePeriod][symbolHistory[timePeriod].Count - 2].DiMinus;

        }

 
 

        //Directional Movement Index Indicator

        if ((sig.DiPlus + sig.DiMinus) != 0)

            sig.Dx = Math.Abs((sig.DiPlus - sig.DiMinus)) / (sig.DiPlus + sig.DiMinus) * 100;

        else

            sig.Dx = symbolHistory[timePeriod][symbolHistory[timePeriod].Count - 2].Dx;

 
 

        //Average Directional Movement Indicator

        if (barHistory[timePeriod].Count <= 2)

        {

            sig.Adx = sig.Dx;

        }

        else

        {

            double a = (double)2 / (double)(calc.DMIPeriod + 1);

            sig.Adx = sig.Dx * a +

                symbolHistory[timePeriod][symbolHistory[timePeriod].Count - 2].Adx * (1 - a);

        }

    }

Sample Data

This is a sample data set consisting of the NYSE A/D 1-min bar data (”Close”) from August 28, 2007 and the 14 period ADX in red.