Skip to content
Jan Boonen edited this page Jun 22, 2016 · 5 revisions

Why this file in TWSApiC++

In my opinion, this TwsApiDefs.h, or something alike, should be part of the basic IB TWS API files. Why? Just ask yourself following questions:

  • what values can I fill in for the order::orderType field and what is the correct spelling.
  • any idea where value 2 stands for in the call eclient->exerciseOptions( id, contract, 2, ...);
  • how can I discover a typo in a string value before even starting testing? Wouldn't that safe a lot of time?
  • how can I discover IB TWS sending new values to my ewrapper string parameters, how can I make my program to discover them when send to my trading program instead of going by unnoticed?

TwsApiDefs.h gives a solution for all these questions.

Note: maintaining this TwsApiDefs.h file should be seen as a collaborate effort because the possibilities of the IB api are extensive and growing, and disovering all possible values is not an easy task in the context of IB TWS API.

Note: The purpose of this text is to explain how to use it, not how it was implemented. See Enumerations.h for the implementation. And yes, it can be used outside this project.

Basics

First, TwsApiDefs.h does the following

  • for each literal value for parameters or fields with finite possibilities, it defines an identifier (via enum) you can use in place of the literal value.
  • it implements some functions that help with the correct formatting of fields like dates etc.

This way, all possible values for parameters and fields are grouped together in one place, easy to discover.

Using these identifiers makes reading the code easier and allows the compiler to check for the correct spelling. I.e. writing OrderType::MRKT will raise a compilation error as the correct spelling is OrderType::MKT, whilst writing 'MRKT' or 'MRK' will both compile. One will work, one not. An ExerciseAction::Lapse is easier to understand then literal value 2.

Examples of functions are

  • EndDateTime(2013,02,20) returns "20130220 00:00:00"
  • DurationStr(1, *DurationHorizon::Months) returns "1 month"

Conversions - when the API expects a String or (const char *) representation

Conversion between the identifiers and their numeric or string representation is possible in different ways. Just read the code to understand it.

 void orderStatus( OrderId orderId, const IBString& status, ... )
 {
 ...
	// from string to its numeric value
	switch( OrderStatus(status) )
	{
		case OrderStatus::PendingSubmit : ... break;
		case OrderStatus::PendingCancel : ... break;
		case OrderStatus::PreSubmitted  : ... break;
		case OrderStatus::Submitted     : ... break;
		case OrderStatus::Cancelled     : ... break;
		case OrderStatus::Filled        : ... break;
		case OrderStatus::_INVALID_     : printf("New unknown status value: %s", (const char*)status); break;
		default:
	}

	// Initialising a variable
	OrderStatus::ENUMS O1; O1 *= status; // can be OrderStatus::_INVALID_

	// or assigning and immediately testing whether the spelling is correct/known in the assignment
	OrderStatus::ENUMS O2;
	if (!(O2 *= status)) {
		// unknown, O2 == OrderStatus::_INVALID_
	}

	// from the identifiers to string
	IBString S1 = *O2; // *OS is of type (const char *), can be "_INVALID_"

	int I1 = O2;
 ...
 }

The case OrderStatus::_INVALID_ catches any (new, unkown) value added by IB but not yet defined in TwsApiC++. At least, you get a message instead of letting it pass unnoticed!

More advanced - iterating through the list of defined values

It is possible to iterate through the different possible values defined for a field or parameter. The file history.cpp shows an possible use. It checks command line parameter value and in case of an error, it dumps the list of known values to the screen.

Just an example with the order::orderType

	for( OrderType::iterator i = OrderType::begin(); i != OrderType::end(); ++i ) {
		printf( "\'%s\', ", i->second );
	}
	printf("\n");

It will print at this moment (version v9.71-01) 'MKT', 'MKTCLS', 'LMT', 'LMTCLS', 'PEGMKT', 'STP', 'STPLMT', 'TRAIL', 'TRAILLIMIT', 'REL', 'VWAP', 'NONE', That seems to be rather an old list According to Basic Orders v9.72 documentation, the list should look like "BOX TOP", "LIT", "LMT", "LOC", "MIT", "MKT PRT", "MKT", "MOC", "MTL", "PASSV REL", "PEG BENCH", "PEG MID", "PEG MKT", "PEG STK", "REL", "Rel + LMT", "Rel + MKT", "STP LMT", "STP PRT", "STP", "TRAIL LIMIT", "TRAIL", "VOL",

Notice the difference i.e. "PEGMKT" and "PEG MKT", it has changed over time?

Maintaining this file

Normally, such file should be maintained by the IB programmers, as they should have defined all these literal values somewhere in their code base. But sadly, as it is not exposed in the API, we have to maintain it our selves.

The current version is not perfect, but definitely a good start. So may I repeat here: keeping this file TwsApiDefs.h up to date should be seen as a collaborate effort - any help is welcome.

Example

Again, a simple example exposes their use and purpose

// Class Player
ENUMValues( Player )                      // Identifier, Numeric value (enum), String representation
  ENUM_N( First                     )     // First     ,  0                  , "First"
  ENUM_N( Second                    )     // Second    ,  1                  , "Second"
  ENUM_V( Third    , 30             )     // Third     , 30                  , "Third"
  ENUM_S( Fourth   , "!Surprice!"   )     // Fourth    , 31                  , "!Surprice!"
  ENUM_S( Fifth    , "#5"           )     // Fifth     , 32                  , "#5"
  ENUMVS( Sixth    , 60 , "LastOne" )     // Sixth     , 60                  , "LastOne"
ENUMFunctions( Player )                   // End the definition with same name Player!


// prints "First", "Second", "Third", "!Surprice!", "#5", "LastOne",
for( Player::iterator i = Player::begin(); i != Player::end(); ++i ) {
	printf( "\'%s\', ", i->second );
}
printf("\n");

printf("%d \'%s\'\n", Player::Fifth, *Player::Fifth);  // 32, "#5"

Player::ENUMS P1; P1 *= "#5";   // Player::Fifth
Player::ENUMS P2(P1);           // Player::Fifth
Player::ENUMS P3;               // Player::_INVALID_
Player::ENUMS P4; P4 *= "oops"; // Player::_INVALID_

printf("%d \'%s\'\n", P1, *P1);  // 32, "#5"
printf("%d \'%s\'\n", P2, *P2);  // 32, "#5"
printf("%d \'%s\'\n", P3, *P3);  // -undefined-, "_INVALID_"
printf("%d \'%s\'\n", P4, *P4);  // 61, "_INVALID_"