示例#1
0
TA_RetCode TA_DictAddPair_S2( TA_Dict *dict,
                              TA_String *key1,
                              TA_String *key2,
                              void *value )
{
   TA_PrivDictInfo *theDict;
   dnode_t *node;
   TA_String *dupKey;
   TA_Dict *subDict;
   TA_Libc *libHandle;
   dict_t  *kazlibDict;

   theDict = (TA_PrivDictInfo *)dict;

   if( (theDict == NULL) ||
       (key1 == NULL) || (key2 == NULL) || (value == NULL) )
      return TA_BAD_PARAM;
   kazlibDict = &theDict->d;
   libHandle  = theDict->libHandle;

   /* Verify if a a dictionary already exist for key1. */
   node = dict_lookup( libHandle, kazlibDict, TA_StringToChar(key1) );

   if( node )
   {
      /* A dictionary already exist with the same key1... re-use it. */
      subDict = (TA_Dict *)dnode_get( node );
   }
   else
   {
      /* Alloc a new directory corresponding to key1. */
      subDict = TA_DictAlloc( libHandle, TA_DICT_KEY_ONE_STRING, theDict->freeValueFunc );

      if( !subDict )
         return TA_ALLOC_ERR;

      dupKey = TA_StringDup( TA_GetGlobalStringCache( libHandle ), key1 );

      if( !dupKey )
      {
         TA_DictFree( subDict );
         return TA_ALLOC_ERR;
      }

      if( !dict_alloc_insert( libHandle, kazlibDict, TA_StringToChar(dupKey), subDict ) )
      {
         TA_DictFree( subDict );
         TA_StringFree( TA_GetGlobalStringCache( libHandle ), dupKey );
         return TA_ALLOC_ERR;
      }
   }

   /* Insert the string in the subDict using key2 */
   return TA_DictAddPair_S( subDict, key2, value );
}
示例#2
0
TA_RetCode TA_DictAddPair_S( TA_Dict *dict,
                             TA_String *key,
                             void *value )
{
   TA_PrivDictInfo *theDict;
   dnode_t *node;
   TA_String *dupKey;
   TA_Libc *libHandle;
   dict_t  *kazlibDict;

   theDict = (TA_PrivDictInfo *)dict;

   if( (theDict == NULL) || (key == NULL) || (value == NULL) )       
      return TA_BAD_PARAM;
   kazlibDict = &theDict->d;
   libHandle  = theDict->libHandle;

   /* Verify if an entry exist already with the same key. */
   node = dict_lookup( libHandle, kazlibDict, TA_StringToChar(key) );

   if( node )
   {
      /* An entry already exist with the same key...
       * Re-use the existing node. Just replace the
       * 'value' part.
       * De-allocate the older 'value'.
       */
      if( theDict->freeValueFunc )
         (*theDict->freeValueFunc)( libHandle, dnode_get( node ) );
      dnode_put( node, value );
   }
   else
   {
      /* Alloc/insert a new key-value pair in the dictionary. */
      dupKey = TA_StringDup( TA_GetGlobalStringCache( libHandle ), key );

      if( !dupKey )
         return TA_ALLOC_ERR;

      if( !dict_alloc_insert( libHandle, kazlibDict, TA_StringToChar(dupKey), value ) )
      {
         TA_StringFree( TA_GetGlobalStringCache( libHandle ), dupKey );
         return TA_ALLOC_ERR;
      }
   }

   return TA_SUCCESS;
}
示例#3
0
/**** Local functions definitions.     ****/
static TA_RetCode doAdjustments( TA_DecodingParam *localDecodingParam,
                                 TA_String *yahooName,
                                 TA_PrivateYahooHandle *yahooHandle,
                                 const char *overideServerAddr,
                                 TA_ParamForAddData  *paramForAddData )
{
   TA_RetCode retCode;
   TA_WebPage *webPage;
   TA_Stream *stream;
   TA_StreamAccess *streamAccess;
   TA_AdjustDataParse adjustDataParse;

   adjustDataParse.paramForAddData = paramForAddData;
   adjustDataParse.yahooHandle = yahooHandle;

   /* Get the split/value adjustments from the Yahoo! web site */
   retCode = TA_WebPageAllocFromYahooName( localDecodingParam,
                                           TA_StringToChar(yahooName),
                                           overideServerAddr,
                                           &webPage, paramForAddData );

   if( retCode != TA_SUCCESS )
      return retCode;

   /* Parse the dividend/split information */
   stream = webPage->content;  
   streamAccess = TA_StreamAccessAlloc( stream );

   if( !streamAccess )
   {
      TA_WebPageFree( webPage );
      return TA_ALLOC_ERR;
   }

   retCode = TA_StreamAccessSearch( streamAccess, "Monthly" );
   if( retCode == TA_SUCCESS )
   {
      retCode = TA_StreamAccessSearch( streamAccess, "Last" );
      if( retCode == TA_SUCCESS )
      {
          /* Find the table of data. */
          retCode = TA_StreamAccessSearch( streamAccess, "yfnc_datamodoutline1" );;
          if( retCode == TA_SUCCESS )
          {
             retCode = TA_StreamAccessGetHTMLTable( streamAccess,
                                                    200,
                                                    processAdjustmentTable,
                                                    &adjustDataParse );
          }
      }
   }

   TA_StreamAccessFree( streamAccess );
   TA_WebPageFree( webPage );

   return retCode;   
}
示例#4
0
TA_RetCode TA_YAHOO_OpenSource( const TA_AddDataSourceParamPriv *param,
                                TA_DataSourceHandle **handle )
{
   TA_PROLOG
   TA_DataSourceHandle *tmpHandle;
   TA_PrivateYahooHandle *privData;
   TA_RetCode retCode;
   TA_StringCache *stringCache;
   TA_CountryId countryId;
   TA_CountryId countryIdTemp;
   TA_Timestamp now;
   const char *locationPtr;
   char locationBuffer[3];
   int timeout_set; /* boolean */
   int i, again;
   unsigned int strLength, strServerLength;
   const char *strTemp;

   *handle = NULL;

   TA_TRACE_BEGIN( TA_YAHOO_OpenSource );

   stringCache = TA_GetGlobalStringCache();

   /* Verify that the requested functionality is supported or not. */
   if( param->flags & TA_REPLACE_ZERO_PRICE_BAR )
   {
      TA_TRACE_RETURN( TA_NOT_SUPPORTED );
   }

   /* Allocate and initialize the handle. This function will also allocate the
    * private handle (opaque data).
    */
   tmpHandle = TA_YAHOO_DataSourceHandleAlloc();

   if( tmpHandle == NULL )
   {
      TA_TRACE_RETURN( TA_ALLOC_ERR );
   }

   privData = (TA_PrivateYahooHandle *)(tmpHandle->opaqueData);

   /* Copy some parameters in the private handle. */
   privData->param = param;
   
   /* Indentify the country and replace with the default as needed.
    * At the same time, identify optional "server=" modifier.
    */
   countryId = TA_Country_ID_INVALID;
   if( privData->param->location )
   {
      locationPtr = TA_StringToChar(privData->param->location);

      /* Split into token (seperator is ';'). Check for a 2 character country 
       * string and the optional "server=" modifier.
       */
      i = -1; 
      strTemp = &locationPtr[0];
      strLength = 0;
      strServerLength = strlen(TA_SERVER_STR);
      again = 1;
      while( (++i < 1024) && again )
      {
         if( strLength == 0 )
            strTemp = &locationPtr[i];

         if( locationPtr[i] == '\0' )
            again = 0;         

         if( locationPtr[i] == ';' || !again )
         {
            if( strLength == 2 )
            {
               locationBuffer[0] = locationPtr[i-2];
               locationBuffer[1] = locationPtr[i-1];
               locationBuffer[2] = '\0';
               countryIdTemp = TA_CountryAbbrevToId(locationBuffer);
               if( countryIdTemp == TA_Country_ID_INVALID )
                  TA_TRACE_RETURN( TA_UNSUPPORTED_COUNTRY );
               if( countryId != TA_Country_ID_INVALID )
                  TA_TRACE_RETURN( TA_LIMIT_OF_ONE_COUNTRY_ID_EXCEEDED );
               countryId = countryIdTemp;         
            }
            else if( strLength>strServerLength && (strncmp(strTemp,TA_SERVER_STR,strServerLength)==0) )
            {              
               if( privData->userSpecifiedServer )
                  TA_TRACE_RETURN( TA_LIMIT_OF_ONE_SERVER_EXCEEDED );
               privData->userSpecifiedServer = TA_StringAllocN( stringCache, 
                                                                &strTemp[strServerLength],
                                                                strLength-strServerLength );
               TA_ASSERT( privData->userSpecifiedServer != NULL );
            }
            else
               TA_TRACE_RETURN( TA_LOCATION_PARAM_INVALID );

            strLength = 0;           
         }
         else
            strLength++;
      }
   }

   if( countryId == TA_Country_ID_INVALID )
   {
      /* Default is United States. */
      countryId = TA_Country_ID_US;
   }

   if( privData->param->id == TA_YAHOO_ONE_SYMBOL )
   {
      privData->index = NULL;
      privData->webSiteCountry = countryId;
      privData->webSiteSymbol  = TA_StringDup(stringCache,privData->param->info);
      tmpHandle->nbCategory = 1;
   }
   else
   {
      /* Build the index using .dat files */
      switch( countryId )
      {
      case TA_Country_ID_US: /* United States */
      case TA_Country_ID_CA: /* Canada */
      case TA_Country_ID_UK: /* United Kingdom */
      case TA_Country_ID_DE: /* Germany */
      case TA_Country_ID_DK: /* Denmark */
      case TA_Country_ID_ES: /* Spain */
      case TA_Country_ID_FR: /* France */
      case TA_Country_ID_IT: /* Italy */
      case TA_Country_ID_SE: /* Sweden */
      case TA_Country_ID_NO: /* Norway */
         /* These country are currently supported. */
         break;
      default:
         TA_YAHOO_DataSourceHandleFree( tmpHandle );
         TA_TRACE_RETURN( TA_UNSUPPORTED_COUNTRY );
      }

      /* Establish the timeout for local cache of the index.
       * Let's make it 4 business days.
       */
      timeout_set = 0;
      TA_SetDefault( &now );
      retCode = TA_SetDateNow( &now );
      for( i=0; (i < 4) && (retCode == TA_SUCCESS); i++ )
         retCode = TA_PrevWeekday( &now );
      if( (i == 4) && (retCode == TA_SUCCESS) )
         timeout_set = 1;
      
      /* At this point, we got all the information we
       * need in the handle.
       * Now build the TA_YahooIdx.
       */
      retCode = TA_YahooIdxAlloc( countryId,
                                  &privData->index,
                                  TA_USE_LOCAL_CACHE|TA_USE_REMOTE_CACHE,
                                  NULL, timeout_set?&now:NULL, NULL );

      if( retCode != TA_SUCCESS )
      {
         TA_YAHOO_DataSourceHandleFree( tmpHandle );
         TA_TRACE_RETURN( retCode );
      }

      /* Set the total number of distinct category. */
      tmpHandle->nbCategory = privData->index->nbCategory;
   }

   *handle = tmpHandle;

   TA_TRACE_RETURN( TA_SUCCESS );
}
示例#5
0
TA_RetCode TA_YAHOO_OpenSource( const TA_AddDataSourceParamPriv *param,
                                TA_DataSourceHandle **handle )
{
   TA_PROLOG
   TA_DataSourceHandle *tmpHandle;
   TA_PrivateYahooHandle *privData;
   TA_RetCode retCode;
   TA_StringCache *stringCache;
   TA_CountryId countryId;
   TA_Timestamp now;
   const char *locationPtr;
   int timeout_set; /* boolean */
   int i;

   *handle = NULL;

   TA_TRACE_BEGIN(  TA_YAHOO_OpenSource );

   stringCache = TA_GetGlobalStringCache();

   /* Verify that the requested functionality is supported or not. */
   if( param->flags & TA_REPLACE_ZERO_PRICE_BAR )
   {
      TA_TRACE_RETURN( TA_NOT_SUPPORTED );
   }

   /* Allocate and initialize the handle. This function will also allocate the
    * private handle (opaque data).
    */
   tmpHandle = TA_YAHOO_DataSourceHandleAlloc();

   if( tmpHandle == NULL )
   {
      TA_TRACE_RETURN( TA_ALLOC_ERR );
   }

   privData = (TA_PrivateYahooHandle *)(tmpHandle->opaqueData);

   /* Copy some parameters in the private handle. */
   privData->param = param;

   /* Validate if this is a supported country. */
   if( !privData->param->location )
   {
      countryId = TA_Country_ID_US;
   }
   else
   {
      locationPtr = TA_StringToChar(privData->param->location);
      countryId = TA_CountryAbbrevToId(locationPtr);
      switch( countryId )
      {
      case TA_Country_ID_US: /* United States */
      case TA_Country_ID_CA: /* Canada */
      case TA_Country_ID_UK: /* United Kingdom */
      case TA_Country_ID_DE: /* Germany */
      case TA_Country_ID_DK: /* Denmark */
      case TA_Country_ID_ES: /* Spain */
      case TA_Country_ID_FR: /* France */
      case TA_Country_ID_IT: /* Italy */
      case TA_Country_ID_SE: /* Sweden */
      case TA_Country_ID_NO: /* Norway */
         /* These country are currently supported. */
         break;
      default:
         TA_YAHOO_DataSourceHandleFree( tmpHandle );
         TA_TRACE_RETURN( TA_UNSUPPORTED_COUNTRY );
      }
   }

   /* Establish the timeout for local cache of the index.
    * Let's make it 3 business days.
    */
   timeout_set = 0;
   TA_SetDefault( &now );
   retCode = TA_SetDateNow( &now );
   for( i=0; (i < 3) && (retCode == TA_SUCCESS); i++ )
      retCode = TA_PrevWeekday( &now );
   if( (i == 3) && (retCode == TA_SUCCESS) )
      timeout_set = 1;
      
   /* At this point, we got all the information we
    * need in the handle.
    * Now build the TA_YahooIdx.
    */
   retCode = TA_YahooIdxAlloc(
                               countryId,
                               &privData->index,
                               TA_USE_LOCAL_CACHE|TA_USE_REMOTE_CACHE,
                               NULL, timeout_set?&now:NULL, NULL );


   if( retCode != TA_SUCCESS )
   {
      TA_YAHOO_DataSourceHandleFree( tmpHandle );
      TA_TRACE_RETURN( retCode );
   }

   /* Set the total number of distinct category. */
   tmpHandle->nbCategory = privData->index->nbCategory;

   *handle = tmpHandle;

   TA_TRACE_RETURN( TA_SUCCESS );
}
示例#6
0
/**** Global functions definitions.   ****/
TA_RetCode TA_GetHistoryDataFromWeb( TA_Libc *libHandle,
                                     TA_DataSourceHandle *handle,
                                     TA_CategoryHandle   *categoryHandle,
                                     TA_SymbolHandle     *symbolHandle,
                                     TA_Period            period,
                                     const TA_Timestamp  *start,
                                     const TA_Timestamp  *end,
                                     TA_Field             fieldToAlloc,
                                     TA_ParamForAddData  *paramForAddData )
{
   TA_PROLOG;

   TA_RetCode retCode;
   TA_StringCache *stringCache;
   TA_String *yahooName;
   TA_WebPage *webPage;
   TA_PrivateYahooHandle *yahooHandle;
   TA_DecodingParam localDecodingParam;
   const TA_DecodingParam *decodingParam;
   TA_FileHandle *fileHandle;
   TA_ReadOpInfo *readOpInfo;
   UIRSuffixParsing suffixParsing;
   TA_Timestamp firstBarTimestamp, lastBarTimestamp, prevEndDate;
   TA_InfoFromAddedData infoFromAddedData;
   TA_DayOfWeek dayOfWeek;

   int nbEstimateBar;
   int nbField;
   unsigned int nbBarAdded, nbTotalBarAdded;
   int again, firstTime, nbBatch;
   int zeroBarAddedAttempt;

   TA_TRACE_BEGIN( libHandle, TA_GetHistoryDataFromWeb );

   /* Initialize some local variables. */
   stringCache   = TA_GetGlobalStringCache( libHandle );
   yahooHandle   = (TA_PrivateYahooHandle *)handle->opaqueData;
   readOpInfo    = NULL;
   nbEstimateBar = 0;

   TA_ASSERT( libHandle, categoryHandle != NULL );
   TA_ASSERT( libHandle, symbolHandle != NULL );
   TA_ASSERT( libHandle, categoryHandle->string != NULL );
   TA_ASSERT( libHandle, symbolHandle->string != NULL );

   /* Set the initial first/last timestamp */
   if( start )
      TA_TimestampCopy( &firstBarTimestamp, start );
   else
   {
      TA_SetDate( 1950, 1, 1, &firstBarTimestamp );
      TA_SetTime( 0, 0, 0, &firstBarTimestamp );
   }

   if( end )
      TA_TimestampCopy( &lastBarTimestamp, end );
   else
   {
      TA_SetDateNow( &lastBarTimestamp );
      TA_SetTime( 0, 0, 0, &lastBarTimestamp );
   }

   /* Make sure that lastBarTimestamp is a week-day. */
   dayOfWeek = TA_GetDayOfTheWeek( &lastBarTimestamp );
   if( (dayOfWeek == TA_SUNDAY) || (dayOfWeek == TA_SATURDAY) )
      TA_PrevWeekday( &lastBarTimestamp );

   /* Map the TA-Lib name into the Yahoo! name. */
   retCode = TA_AllocStringFromLibName( libHandle,
                                        categoryHandle->string,
                                        symbolHandle->string,
                                        &yahooName );  
   if( retCode != TA_SUCCESS )
   {
      TA_TRACE_RETURN( retCode );
   }

   TA_ASSERT( libHandle, yahooName != NULL );
   TA_ASSERT( libHandle, yahooHandle != NULL );

   /* Get the decoding parameter for the CSV web page. */
   decodingParam = TA_YahooIdxDecodingParam( yahooHandle->index, TA_YAHOOIDX_CVS_PAGE );
   if( !decodingParam )
   {
      TA_StringFree( stringCache, yahooName );
      TA_TRACE_RETURN( TA_INTERNAL_ERROR(103) );
   }

   /* Use a local copy of the decoding param. 
    * This is because the uirSuffix is replaced with
    * an allocated buffer (so the date field can be
    * manipulated).
    */
   localDecodingParam = *decodingParam;

   /* Parse the uirSuffix so the start/end date can be changed. */
   if( !setUIRSuffixParsing( decodingParam->uirSuffix, &suffixParsing ) )
   {
      /* This should never happen unless the
       * Yahoo! index protocol has been broken.
       */
      /* Clean-up and exit */
      TA_StringFree( stringCache, yahooName );
      TA_TRACE_RETURN( TA_INTERNAL_ERROR(104) );
   }

   /* Replace the uirSuffix with a large local buffer. */
   localDecodingParam.uirSuffix = TA_Malloc( libHandle, suffixParsing.maxTotalLength );
   if( !localDecodingParam.uirSuffix )
   {
      /* Clean-up and exit */
      TA_StringFree( stringCache, yahooName );
      TA_TRACE_RETURN( TA_ALLOC_ERR );
   }

   /* Change the dates in the uirSuffix. */
   buildUIRSuffix( &suffixParsing,
                   &firstBarTimestamp, &lastBarTimestamp,
                   (char *)localDecodingParam.uirSuffix );

   /* nbBatch is a safety net to make sure that
    * TA-Lib won't stay forever in the while loop
    * in case Yahoo! changes their protocol.
    */
   nbBatch = 0; 

   /* Sometime Yahoo! return an empty csv file. Make
    * multiple attempts in that case.
    */
   zeroBarAddedAttempt = 0;

   again = 1;
   firstTime = 1;
   nbTotalBarAdded = 0;
   while( again && (++nbBatch < 100) && (zeroBarAddedAttempt < 10) )
   {  
    
      if( TA_TimestampLess(&lastBarTimestamp,&firstBarTimestamp) )
      {
          /* Get out of this loop if all the requested data
           * has been retreived already.
           */
         again = 0;
         break;
      }   

      retCode = TA_WebPageAllocFromYahooName( libHandle,
                                              &localDecodingParam,
                                              TA_StringToChar(yahooName),
                                              &webPage );
           
      if( retCode != TA_SUCCESS )
      {
         TA_StringFree( stringCache, yahooName );
         TA_Free( libHandle, (char *)localDecodingParam.uirSuffix );
         TA_TRACE_RETURN( retCode );
      }

      /* Disguise the webPage stream into a "file". That way the speed
       * optimized ASCII decoder can be re-used (TA_ReadOp stuff).
       */
      retCode = TA_FileSeqOpenFromStream( libHandle, webPage->content, &fileHandle );
      if( retCode != TA_SUCCESS )
      {
         /* Clean-up and exit */
         TA_StringFree( stringCache, yahooName );
         TA_WebPageFree( webPage );
         TA_Free( libHandle, (char *)localDecodingParam.uirSuffix );
         TA_TRACE_RETURN( retCode );
      }

      if( firstTime )
      {
         /* Make assumption of the data provided
          * base on the number of fields in the CSV file.
          */
         nbField = nbCommaField( webPage->content );
         switch( nbField )
         {
         case 2:
            readOpInfo = yahooHandle->readOp2Fields;
            break;
         case 5:
            readOpInfo = yahooHandle->readOp5Fields;
            break;
         default:
            readOpInfo = yahooHandle->readOp6Fields;
         }

         /* User asking for all the fields? */
         if( fieldToAlloc == TA_ALL )
         {
            switch( nbField )
            {
            case 2:
               fieldToAlloc = TA_CLOSE|TA_TIMESTAMP;
               break;
            case 5:
               fieldToAlloc = TA_OPEN|TA_HIGH|TA_LOW|TA_CLOSE|TA_TIMESTAMP;
               break;
            default:
               fieldToAlloc = TA_OPEN|TA_HIGH|TA_LOW|TA_CLOSE|TA_VOLUME|TA_TIMESTAMP;
            }
         }

         /* Optimize the read op for the requested data. */
         retCode = TA_ReadOp_Optimize( libHandle,
                                       readOpInfo,
                                       period,
                                       fieldToAlloc );
         if( retCode != TA_SUCCESS )
         {
            /* Clean-up and exit */
            TA_StringFree( stringCache, yahooName );
            TA_WebPageFree( webPage );
            TA_Free( libHandle, (char *)localDecodingParam.uirSuffix );
            TA_TRACE_RETURN( retCode );
         }

         /* Make an estimation of the number of price bar. */
         nbEstimateBar  = TA_StreamCountChar( webPage->content, '\n' ) + 1;
         if( nbEstimateBar < 100 )
            nbEstimateBar = 100;
      }

      /* Interpret the CSV data. */
      retCode = TA_ReadOp_Do( libHandle, fileHandle,                           
                              readOpInfo,
                              period, &firstBarTimestamp, &lastBarTimestamp,
                              nbEstimateBar, fieldToAlloc,
                              paramForAddData,
                              &nbBarAdded );

      TA_FileSeqClose( libHandle, fileHandle );
      TA_WebPageFree( webPage );

      nbTotalBarAdded += nbBarAdded;

      if( retCode != TA_SUCCESS )
      {
         /* Clean-up and exit */
         TA_StringFree( stringCache, yahooName );
         TA_Free( libHandle, (char *)localDecodingParam.uirSuffix );
         TA_TRACE_RETURN( retCode );
      }

      /* Yahoo! does not always return all the data it could, up to
       * the requested end date. It is important to detect these occurence
       * and cancel the usage of all data accumulated up to now. 
       */      
      TA_GetInfoFromAddedData( paramForAddData, &infoFromAddedData );
      if( infoFromAddedData.barAddedSinceLastCall )
      {
         /* Do some more checking by considering holidays, week-end etc... */
         if( !isGapAcceptable(&infoFromAddedData.highestTimestampAddedSinceLastCall, &lastBarTimestamp) )
         {
            /* Clean-up and exit */
            TA_StringFree( stringCache, yahooName );
            TA_Free( libHandle, (char *)localDecodingParam.uirSuffix );
            TA_TRACE_RETURN( TA_DATA_GAP );
         }
         
         TA_TimestampCopy( &lastBarTimestamp, &infoFromAddedData.lowestTimestamp );
      }

      #if DEBUG_PRINTF
      printf( "NB BAR ADDED=%d, TOTAL=%d\n", nbBarAdded, nbTotalBarAdded );
      #endif

      /* Verify if more data should be processed. 
       * Yahoo! sometimes slice their data, in 
       * batch of 200 price bars. 
       */
      if( firstTime && (nbBarAdded > 200) )
      {
         again = 0; /* Assume all the data extracted... exit the loop. */
      }
      else if( nbBarAdded == 0 )
      {
         /* Make multiple attempts when retreiving data succeed,
          * but somehow there is zero bar returned. 
          *
          * Sometimes this might be correct when there is truly no
          * more data available, so choosing an algorithm before
          * giving up is a comprimise between reliability and
          * usability. The data source is free... and you get
          * what you pay for after all ;)
          */
         if( (nbTotalBarAdded < 1000) && (zeroBarAddedAttempt >= 1) && (zeroBarAddedAttempt < 7) )
         {
            /* I did choose to add a delay when insufficient total data is returned. When
             * there is already ~5 years of data, most likely there is "Zero" returned
             * because there is NO more data available, so just do the retry without delay.
             */
            TA_Sleep(zeroBarAddedAttempt*2);
         }

         #if DEBUG_PRINTF
         printf( "Retry %d", zeroBarAddedAttempt );
         #endif

         zeroBarAddedAttempt++;
      }
      else
      {
         zeroBarAddedAttempt = 0;

         if( TA_TimestampEqual( &lastBarTimestamp, &prevEndDate ) )
         {
            /* prevEndDate is a "safety net" to
             * exit the loop early in case Yahoo! starts
             * to return always the same batch of data.
             * Just ignore the repetitive data and exit.
             */
            TA_Free( libHandle, (char *)localDecodingParam.uirSuffix );
            TA_StringFree( stringCache, yahooName );
            TA_TRACE_RETURN( TA_SUCCESS );
         }
         TA_TimestampCopy( &prevEndDate, &lastBarTimestamp );

         /* Request the data up to the day BEFORE
          * the last batch of data received.
          */
         TA_PrevDay( &lastBarTimestamp );

         /* Make sure that lastBarTimestamp is a week-day. */
         dayOfWeek = TA_GetDayOfTheWeek( &lastBarTimestamp );
         if( (dayOfWeek == TA_SUNDAY) || (dayOfWeek == TA_SATURDAY) )
            TA_PrevWeekday( &lastBarTimestamp );

         /* Change the dates in the uirSuffix. */
         buildUIRSuffix( &suffixParsing,
                         &firstBarTimestamp, &lastBarTimestamp,
                         (char *)localDecodingParam.uirSuffix );

         /* From that point, data is expected to be most likely
          * sent in batch of 200.
          */
         nbEstimateBar = 200;
      }

      firstTime = 0;
   }

   /* Clean-up and exit */
   TA_Free( libHandle, (char *)localDecodingParam.uirSuffix );
   TA_StringFree( stringCache, yahooName );
   TA_TRACE_RETURN( retCode );
}
示例#7
0
/**** Global functions definitions.   ****/
TA_RetCode TA_FileIndexParsePath( TA_FileIndexPriv *fileIndexPriv, TA_String *path )
{
   typedef enum { INIT_PROCESSING,
                  FIX_PROCESSING,
                  FIELD_PROCESSING,
                  WILD_PROCESSING,
                  SEP_PROCESSING } State;

   TA_PROLOG
   State currentState;
   const char *currentTokenStart;
   unsigned int length;
   char *str;
   char *pos;
   char sepTmp[2];
   TA_RetCode retCode;
   unsigned int tokenSize;
   TA_TokenId tokenId;
   const char *sourcePattern;

   TA_TRACE_BEGIN(  TA_FileIndexParsePath );

   TA_ASSERT( path != NULL );

   sepTmp[1] = '\0';
   sourcePattern = TA_StringToChar( path );

   /* The following macro should help for the readability of the parsing logic.
    * These macro are used only inside this function.
    */
   #define RETURN(y) {TA_Free(str); TA_TRACE_RETURN( y );}
   #define REJECT_STATE(x,y) { if(currentState==x)RETURN(y);  }
   #define CHANGE_STATE(x) {currentState=x; currentTokenStart=pos+1;}

   #define ADD_TOKEN(id,value) \
   { \
      retCode = addToken(fileIndexPriv,id,value); \
      if( retCode != TA_SUCCESS) RETURN(retCode); \
   }

   #define FLUSH_FIX() \
   { \
      retCode = flushFixPart(fileIndexPriv,currentTokenStart,pos); \
      if( retCode != TA_SUCCESS ) RETURN(retCode); \
   }

   /* This function build a list representing the tokens
    * of the sourcePattern.
    *
    * Example:  "C:\a\*AZD?\[S]\data.txt" becomes
    *
    *            TokenId      Value
    *            TA_TOK_FIX       "C:"
    *            TA_TOK_SEP       "\"
    *            TA_TOK_FIX       "a"
    *            TA_TOK_SEP       "\"
    *            TA_TOK_WILD      "*"
    *            TA_TOK_FIX       "AZD"
    *            TA_TOK_WILD_CHAR "?"
    *            TA_TOK_SEP       "\"
    *            TA_TOK_S         "?*"
    *            TA_TOK_SEP       "\"
    *            TA_TOK_FIX       "data.txt"
    *            TA_TOK_END       (null)
    *
    *        In the values, the '?' and '*' character represent MS-DOS kind
    *        of wildcards:
    *             '?' is any character (but only one).
    *             '*' zero or more of any character
    */
   if( sourcePattern == NULL )
      return TA_INVALID_PATH;

   length = strlen( sourcePattern ) + 1;

   if( (length <= 1) || (length > 2048) )
      return TA_INVALID_PATH;

   str = (char *)TA_Malloc( length );
   strcpy( str, sourcePattern );

   pos = str;
   currentState = INIT_PROCESSING;
   currentTokenStart = pos;

   while( *pos != '\0' )
   {

      if( (*pos == '\\') || (*pos == '/') )
      {
         /* Handle directories separator character. */
         REJECT_STATE( FIELD_PROCESSING, TA_INVALID_FIELD );
         REJECT_STATE( SEP_PROCESSING, TA_INVALID_PATH );

         FLUSH_FIX();

#if 0
!!! Needed?
         /* Check that the string prior to the separator
          * does not terminate with a dot '.'
          */
         if( currentState != INIT_PROCESSING )
         {
            if( *(pos-1) == '.' )
               RETURN( TA_INVALID_PATH );
         }
#endif
         /* Transform into the directory delimiter
          * used on the host file system.
          */
         sepTmp[0] = (char)TA_SeparatorASCII();
         ADD_TOKEN( TA_TOK_SEP, sepTmp );

         CHANGE_STATE( SEP_PROCESSING );
      }
      else switch( *pos )
示例#8
0
static void internalCheckpoint( TA_TraceGlobal *global,
                                TA_String  *key,
                                const char *funcname,
                                const char *filename,
                                unsigned int lineNb )
{
   #if !defined( TA_SINGLE_THREAD )      
   TA_RetCode retCode;
   #endif

   #ifdef TA_DEBUG
   TA_TracePosition *tracePosition;
   #endif

   /* Make sure there is no tracing while tracing!
    * In rare occasion, this may prevent to record
    * some tracing in a multithread environment.
    * We can live with that compromise.
    */   
   if( !TA_IsTraceEnabled() )
      return;

   #if !defined( TA_SINGLE_THREAD )                   
      retCode = TA_SemaWait( &global->callSema );
      if( retCode != TA_SUCCESS )
         return;   
   #endif

   #ifdef TA_DEBUG
   /* If this position is already in the dictionary, just
    * increment the 'repetition' counter, else create
    * a new entry in the dictionary.
    */
   TA_TraceDisable();
   tracePosition = TA_DictGetValue_S( global->functionCalled, TA_StringToChar(key) );
   TA_TraceEnable();

   if( tracePosition )
      tracePosition->repetition++;
   else
   {
      tracePosition = newTracePosition( funcname, filename, lineNb );

      if( !tracePosition )
      {
         #if !defined( TA_SINGLE_THREAD )
            TA_SemaPost( &global->callSema );
         #endif
         return;
      }
      TA_TraceDisable();
      TA_DictAddPair_S( global->functionCalled, key, (void *)tracePosition );
      TA_TraceEnable();
   }
   /* Trace position are never deleted, until the library is shutdown.
    * Make a copy of it in the circular buffer.
    */
   global->codeTrace[global->posForNextTrace] = *tracePosition;
   #else
      (void)key; /* Used only when doing debug. */
      global->codeTrace[global->posForNextTrace].filename   = filename;
      global->codeTrace[global->posForNextTrace].funcname   = funcname;
      global->codeTrace[global->posForNextTrace].lineNb     = lineNb;
      global->codeTrace[global->posForNextTrace].repetition = 1;
   #endif

   /* Move to the next entry in the circular buffer. */
   global->posForNextTrace++;
   if( global->posForNextTrace >= TA_CODE_TRACE_SIZE )
      global->posForNextTrace = 0;

   #if !defined( TA_SINGLE_THREAD )
   TA_SemaPost( &global->callSema );
   #endif
}
示例#9
0
TA_RetCode TA_SIMULATOR_OpenSource( const TA_AddDataSourceParamPriv *param,
                                    TA_DataSourceHandle **handle )
{
   TA_PROLOG
   TA_DataSourceHandle *tmpHandle;
   TA_PrivateHandle *privData;
   TA_StringCache *stringCache;

   *handle = NULL;

   TA_TRACE_BEGIN(  TA_SIMULATOR_OpenSource );

   stringCache = TA_GetGlobalStringCache();

   if( !stringCache )
   {
      TA_TRACE_RETURN( TA_INTERNAL_ERROR(91) );
   }

   /* Verify that the requested functionality is supported or not. */
   if( param->flags & TA_REPLACE_ZERO_PRICE_BAR )
   {
      TA_TRACE_RETURN( TA_NOT_SUPPORTED );
   }

   /* Allocate and initialize the handle. This function will also allocate the
    * private handle (opaque data).
    */
   tmpHandle = (TA_DataSourceHandle *)TA_Malloc( sizeof( TA_DataSourceHandle ) );

   if( tmpHandle == NULL )
   {
      TA_TRACE_RETURN( TA_ALLOC_ERR );
   }
   memset( tmpHandle, 0, sizeof( TA_DataSourceHandle ) );

   privData = (TA_PrivateHandle *)TA_Malloc( sizeof( TA_PrivateHandle ) );
   if( !privData )
   {
      TA_Free(  tmpHandle );
      TA_TRACE_RETURN( TA_ALLOC_ERR );
   }
   memset( privData, 0, sizeof( TA_PrivateHandle ) );

   tmpHandle->opaqueData = privData;

   /* Copy some parameters in the private handle. */
   privData->categoryIter = 0;   
   privData->catRefIter   = 0;
   privData->catMrgIter   = 0;

   if( param->info == NULL )
   {
      privData->mrgInstance = 0;
      tmpHandle->nbCategory = 1;
   }
   else
   {
      privData->mrgInstance = atoi( TA_StringToChar( param->info ) );

      if( (privData->mrgInstance < 1) || (privData->mrgInstance > 4) )
      {
         TA_Free(  tmpHandle );
         TA_Free(  privData );
         TA_TRACE_RETURN( TA_BAD_PARAM );
      }

      tmpHandle->nbCategory = 2;

      /* Allocate the data. */
      
   }

   /* Pre-allocate all the string used in this data source. */
   privData->ta_sim_ref_cat = TA_StringAlloc(stringCache, "TA_SIM_REF");
   privData->ta_sim_mrg_cat = TA_StringAlloc(stringCache, "TA_SIM_MRG");
   privData->daily_ref_0    = TA_StringAlloc(stringCache, "DAILY_REF_0");
   privData->intra_ref_0    = TA_StringAlloc(stringCache, "INTRA_REF_0");
   privData->mrg_0          = TA_StringAlloc(stringCache, "MRG_0");

   if( !privData->ta_sim_ref_cat ||
       !privData->ta_sim_mrg_cat ||
       !privData->daily_ref_0 ||
       !privData->intra_ref_0 ||
       !privData->mrg_0 )
   {
      freePrivateHandle( privData );
      TA_TRACE_RETURN( TA_ALLOC_ERR );
   }

   /* Everything is fine, return the handle to the caller. */
   *handle = tmpHandle;

   TA_TRACE_RETURN( TA_SUCCESS );
}
示例#10
0
TA_RetCode TA_TradeLogAdd( TA_TradeLog    *tradeLog,
                           const TA_Transaction *newTransaction )
{
    TA_TradeLogPriv *tradeLogPriv;
    TA_Instrument *id;
    TA_Dict *theDict;
    TA_DataLog *dataLog;
    TA_TradeDictEntry *dictEntry;
    TA_StringCache *stringCache;
    TA_String *catString;
    TA_String *symString;
    const char *catCharPtr;
    const char *symCharPtr;
    TA_RetCode retCode;
    int quantity, entryTradeQuantity;
    TA_List *entryListToUse;
    TA_DataLog *entryTradeLog;

    TA_Real highestLow, highestHigh, lowestLow, lowestHigh;
    TA_Real entryPrice, tempReal;
    int i;

    retCode = TA_INTERNAL_ERROR(120);

    /* This function will transform the TA_Transaction into
     * an "entry" or multiple "trades" (because an exit can
     * be translated into multiple trade if there was multiple
     * entry point).
     */
    if( !tradeLog || !newTransaction )
        return TA_BAD_PARAM;

    /* Check that the TA_Transaction makes sense. */
    if( (newTransaction->price <= 0.0)  ||
            (newTransaction->quantity <= 0) ||
            (TA_TimestampValidate(&newTransaction->timestamp) != TA_SUCCESS) ||
            (newTransaction->type >= TA_NB_TRADE_TYPE))
        return TA_BAD_PARAM;

    /* Get access to the hidden data of the TA_TradeLog. */
    tradeLogPriv = (TA_TradeLogPriv *)tradeLog->hiddenData;

    /* Make sure this is a valid object. */
    if( !tradeLogPriv || (tradeLogPriv->magicNb != TA_TRADELOGPRIV_MAGIC_NB) )
        return TA_BAD_OBJECT;

    /* Find the TA_TradeDictEntry corresponding to
     * the TA_Instrument.
     *
     * Use the dictionary corresponding to the type of
     * key of the TA_Instrument.
     *
     * If TA_Instrument is NULL, use the pre-allocated
     * default TA_TradeDictEntry.
     */
    id = newTransaction->id;
    if( !id )
    {
        dictEntry = &tradeLogPriv->defaultDictEntry;
        catCharPtr = NULL;
        symCharPtr = NULL;
        theDict    = NULL;
    }
    else
    {
        catCharPtr = id->catString;
        symCharPtr = id->symString;
        if( catCharPtr )
        {
            if( symCharPtr )
            {
                theDict = tradeLogPriv->tradeDictCATSYM;
                dictEntry = TA_DictGetValue_S2( theDict, catCharPtr, symCharPtr );
            }
            else
            {
                theDict = tradeLogPriv->tradeDictCAT;
                dictEntry = TA_DictGetValue_S( theDict, catCharPtr );
            }
        }
        else if( symCharPtr )
        {
            theDict = tradeLogPriv->tradeDictCAT;
            dictEntry = TA_DictGetValue_S( theDict, symCharPtr );
        }
        else
        {
            theDict = tradeLogPriv->tradeDictUserKey;
            dictEntry = TA_DictGetValue_I( theDict, id->userKey );
        }
    }

    if( !dictEntry )
    {
        if( !theDict )
            return TA_INTERNAL_ERROR(146);

        /* The TA_TradeDictEntry was not found, create it! */
        dictEntry = TA_Malloc( sizeof( TA_TradeDictEntry ) );
        if( !dictEntry )
            return TA_ALLOC_ERR;

        memset( &dictEntry->id, 0, sizeof(TA_Instrument) );
        TA_ListInit( &dictEntry->shortEntryPrivList );
        TA_ListInit( &dictEntry->longEntryPrivList );

        /* Add the dictEntry to the corresponding dictionary. */
        stringCache = TA_GetGlobalStringCache();

        if( catCharPtr )
        {
            catString = TA_StringAlloc( stringCache, catCharPtr );
            if( !catString )
            {
                TA_Free( dictEntry );
                return TA_ALLOC_ERR;
            }

            if( symCharPtr )
            {
                symString = TA_StringAlloc( stringCache, symCharPtr );
                if( !symString )
                {
                    TA_Free( dictEntry );
                    TA_StringFree( stringCache, catString );
                    return TA_ALLOC_ERR;
                }
                retCode = TA_DictAddPair_S2( theDict, catString, symString, dictEntry );
                dictEntry->id.symString = TA_StringToChar(symString);
            }
            else
                retCode = TA_DictAddPair_S( theDict, catString, dictEntry );

            dictEntry->id.catString = TA_StringToChar(catString);
        }
        else if( symCharPtr )
        {
            symString = TA_StringAlloc( stringCache, symCharPtr );
            if( !symString )
            {
                TA_Free( dictEntry );
                return TA_ALLOC_ERR;
            }

            retCode = TA_DictAddPair_S( theDict, symString, dictEntry );
            dictEntry->id.symString = TA_StringToChar(symString);
        }
        else
        {
            retCode = TA_DictAddPair_I( theDict, id->userKey, dictEntry );
            dictEntry->id.userKey = id->userKey;
        }

        /* Check the retCode of the TA_DictAddXXXXX function. */
        if( retCode != TA_SUCCESS )
        {
            TA_Free( dictEntry );
            return TA_ALLOC_ERR;
        }
    }

    /* Identify the approriate list of entry. */
    switch( newTransaction->type )
    {
    case TA_LONG_ENTRY:
    case TA_LONG_EXIT:
        entryListToUse = &dictEntry->longEntryPrivList;
        break;
    case TA_SHORT_ENTRY:
    case TA_SHORT_EXIT:
        entryListToUse = &dictEntry->shortEntryPrivList;
        break;
    default:
        return TA_BAD_PARAM;
    }

    /* The sign of the quantity indicates if the
     * data log is a completed trade (+) or an
     * entry (-).
     */
    switch( newTransaction->type )
    {
    case TA_LONG_ENTRY:
    case TA_SHORT_ENTRY:
        /* Allocate a data log and add it to the list. */
        dataLog = TA_AllocatorForDataLog_Alloc( &tradeLogPriv->allocator );
        if( !dataLog )
            return TA_ALLOC_ERR;
        dataLog->u.entry.quantity  = -(newTransaction->quantity);
        dataLog->u.entry.entryPrice = newTransaction->price;
        TA_TimestampCopy( &dataLog->u.entry.entryTimestamp,
                          &newTransaction->timestamp );
        TA_ListNodeAddTail( entryListToUse, &dataLog->u.entry.node, dataLog );
        break;

    case TA_LONG_EXIT:
    case TA_SHORT_EXIT:
        /* Invalidate cached calculation of this trade log. */
        tradeLogPriv->flags &= ~TA_PMVALUECACHE_CALCULATED;

        /* Transform this transaction into one or
         * multiple trade(s).
         */
        entryTradeLog = TA_ListRemoveHead( entryListToUse );
        if( !entryTradeLog )
            return TA_ENTRY_TRANSACTION_MISSING;

        quantity = newTransaction->quantity;
        while( quantity )
        {
            entryTradeQuantity = -entryTradeLog->u.trade.quantity;
            if( entryTradeQuantity == quantity )
            {
                /* This entry have exactly the right amount of
                 * position for what needs to be closed.
                 * Just transform the entry into a trade.
                 */
                entryTradeLog->u.trade.quantity = quantity;
                entryTradeLog->u.trade.id = id;
                TA_TimestampCopy( &entryTradeLog->u.trade.exitTimestamp,
                                  &newTransaction->timestamp );
                /* Calculate the profit and make the entryPrice
                 * negative if this is a short trade.
                 * Both are multiplied by the quantity being
                 * traded.
                 */
                entryPrice = entryTradeLog->u.entry.entryPrice;
                if( newTransaction->type == TA_LONG_EXIT )
                {
                    entryTradeLog->u.trade.profit = (newTransaction->price-entryPrice)*quantity;
                    CALC_EXCURSION_LONG;
                }
                else
                {
                    entryTradeLog->u.trade.profit = (entryPrice-newTransaction->price)*quantity;
                    entryPrice = -entryPrice;
                    CALC_EXCURSION_SHORT;
                }
                entryTradeLog->u.entry.entryPrice = entryPrice * quantity;

                return TA_SUCCESS; /* Done! */
            }
            else if( entryTradeQuantity < quantity )
            {
                /* This entry have less than the amount of
                 * position that needs to be closed.
                 * Just transform the entry into a trade
                 * and move to the next entry.
                 */
                entryTradeLog->u.trade.quantity = entryTradeQuantity;
                quantity -= entryTradeQuantity;
                entryTradeLog->u.trade.id = id;
                TA_TimestampCopy( &entryTradeLog->u.trade.exitTimestamp,
                                  &newTransaction->timestamp );
                /* Calculate the profit and make the entryPrice
                 * negative if this is a short trade.
                 * Both are multiplied by the quantity being
                 * traded.
                 */
                entryPrice = entryTradeLog->u.trade.entryPrice;
                if( newTransaction->type == TA_LONG_EXIT )
                {
                    entryTradeLog->u.trade.profit = (newTransaction->price-entryPrice)*entryTradeQuantity;
                    CALC_EXCURSION_LONG;
                }
                else
                {
                    entryTradeLog->u.trade.profit = (entryPrice-newTransaction->price)*entryTradeQuantity;
                    entryPrice = -entryPrice;
                    CALC_EXCURSION_SHORT;
                }
                entryTradeLog->u.trade.entryPrice = entryPrice * entryTradeQuantity;

                /* Move to the next entry. If none available, that means there
                 * was more "exit" than "entry" and this is considered an
                 * error.
                 */
                entryTradeLog = TA_ListRemoveHead( entryListToUse );
                if( !entryTradeLog )
                    return TA_ENTRY_TRANSACTION_MISSING;
            }
            else
            {
                /* This entry have more position than what the
                 * exit requires, so the entry must be preserved.
                 * Consequently, a new tradeLog must be allocated.
                 */
                dataLog = TA_AllocatorForDataLog_Alloc( &tradeLogPriv->allocator );
                if( !dataLog )
                    return TA_ALLOC_ERR;

                TA_TimestampCopy( &dataLog->u.trade.entryTimestamp,
                                  &entryTradeLog->u.trade.entryTimestamp );
                TA_TimestampCopy( &dataLog->u.trade.exitTimestamp,
                                  &newTransaction->timestamp );
                dataLog->u.trade.quantity = quantity;
                entryPrice = entryTradeLog->u.trade.entryPrice;
                if( newTransaction->type == TA_LONG_EXIT )
                {
                    dataLog->u.trade.profit = (newTransaction->price-entryPrice)*quantity;
                    CALC_EXCURSION_LONG;
                }
                else
                {
                    dataLog->u.trade.profit = (entryPrice-newTransaction->price)*quantity;
                    entryPrice = -entryPrice;
                    CALC_EXCURSION_SHORT;
                }
                dataLog->u.trade.entryPrice = entryPrice*quantity;
                dataLog->u.trade.id = id;

                /* Adjust the entry and put it back for being process
                 * again later.
                 */
                entryTradeLog->u.trade.quantity += quantity;
                TA_ListNodeAddHead( entryListToUse, &entryTradeLog->u.entry.node, entryTradeLog );
                return TA_SUCCESS; /* Done! */
            }
        }
        break;
    default:
        return TA_INTERNAL_ERROR(121);
    }

    return TA_SUCCESS;
}
示例#11
0
TA_RetCode TA_FileIndexAddSymbolData( TA_Libc *libHandle,
                                      TA_FileIndexCategoryData *categoryData,
                                      TA_String *stringSymbol,
                                      TA_ValueTreeNode *treeNodeValue,
                                      TA_FileIndexSymbolData **added )
{
   TA_PROLOG;
   TA_RetCode retCode;
   TA_FileIndexSymbolData *symbolData;
   unsigned int tmpInt;
   unsigned int symbolFound; /* Boolean */
   TA_StringCache *stringCache;

   TA_TRACE_BEGIN( libHandle, TA_FileIndexAddSymbolData );

   stringCache = TA_GetGlobalStringCache( libHandle );

   TA_ASSERT( libHandle, categoryData != NULL );
   TA_ASSERT( libHandle, categoryData->listSymbol != NULL );
   TA_ASSERT( libHandle, stringSymbol != NULL );
   TA_ASSERT( libHandle, treeNodeValue != NULL );

   if( added )
      *added = NULL;

   /* Trap the case where this symbol is already there for that
    * category. In that case, the information is ignored.
    * Under the same category, for the same datasource, only one file
    * is supported for a category-symbol pair.
    */
   symbolData = (TA_FileIndexSymbolData *)TA_ListAccessTail( categoryData->listSymbol );

   symbolFound = 0;
   while( symbolData && !symbolFound )
   {
      TA_ASSERT( libHandle, symbolData->string != NULL );

      tmpInt = strcmp( TA_StringToChar( stringSymbol ),
                       TA_StringToChar( symbolData->string ) );
      if( tmpInt == 0 )
         symbolFound = 1;
      else
         symbolData = (TA_FileIndexSymbolData *)TA_ListAccessPrev( categoryData->listSymbol );
   }

   if( !symbolFound )
   {
      /* This is a new symbol, so allocate the TA_FileIndexSymbolData */
      symbolData = (TA_FileIndexSymbolData *)TA_Malloc( libHandle, sizeof(TA_FileIndexSymbolData) );

      if( !symbolData )
      {
         TA_TRACE_RETURN( TA_ALLOC_ERR );
      }

      /* Initialize the TA_FileIndexSymbolData */
      symbolData->parent = categoryData;
      symbolData->node   = treeNodeValue;
      symbolData->string = TA_StringDup( stringCache, stringSymbol );
      if( !symbolData->string )
      {
         TA_Free( libHandle, symbolData );
         TA_TRACE_RETURN( TA_ALLOC_ERR );
      }

      /* Add it to the category list. */
      retCode = TA_ListAddTail( categoryData->listSymbol, symbolData );
      if( retCode != TA_SUCCESS )
      {
         TA_StringFree( stringCache, symbolData->string );
         TA_Free( libHandle, symbolData );
         TA_TRACE_RETURN( TA_ALLOC_ERR );
      }
   }

   /* Return the address of the object representing that symbol. */
   if( added )
      *added = symbolData;


   TA_TRACE_RETURN( TA_SUCCESS );
}
示例#12
0
TA_RetCode TA_FileIndexAddCategoryData( TA_FileIndexPriv *data,
                                        TA_String *stringCategory,
                                        TA_FileIndexCategoryData **added )
{
   TA_PROLOG;
   TA_RetCode retCode;
   TA_FileIndexCategoryData *categoryData;
   unsigned int tmpInt;
   unsigned int categoryFound; /* Boolean */
   TA_Libc *libHandle;
   TA_StringCache *stringCache;

   libHandle   = data->libHandle;
   TA_TRACE_BEGIN( libHandle, TA_FileIndexAddCategoryData );

   stringCache = TA_GetGlobalStringCache( libHandle );

   TA_ASSERT( libHandle, data != NULL );
   TA_ASSERT( libHandle, stringCategory != NULL );

   /* Trap the case where the category is already added. */
   categoryData = (TA_FileIndexCategoryData *)TA_ListAccessTail( data->listCategory );

   categoryFound = 0;
   while( categoryData && !categoryFound )
   {
      TA_ASSERT( libHandle, categoryData->string != NULL );

      tmpInt = strcmp( TA_StringToChar( stringCategory ),
                       TA_StringToChar( categoryData->string ) );
      if( tmpInt == 0 )
         categoryFound = 1;
      else
         categoryData = (TA_FileIndexCategoryData *)TA_ListAccessPrev( data->listCategory );
   }

   if( !categoryFound )
   {
      /* This is a new category, so allocate the TA_FileIndexCategoryData */
      categoryData = (TA_FileIndexCategoryData *)TA_Malloc( libHandle, sizeof(TA_FileIndexCategoryData) );

      if( !categoryData )
         TA_TRACE_RETURN( TA_ALLOC_ERR );

      /* Initialize the TA_FileIndexCategoryData */
      categoryData->parent = data;
      if( stringCategory )
      {
         categoryData->string = TA_StringDup( stringCache, stringCategory);    /* String for this category. Can be NULL. */
         if( !categoryData->string )
         {
            TA_Free( libHandle, categoryData );
            TA_TRACE_RETURN( TA_ALLOC_ERR );
         }
      }
      else
         categoryData->string = NULL;

      categoryData->listSymbol = TA_ListAlloc( libHandle );

      if( !categoryData->listSymbol )
      {
         if( categoryData->string )
            TA_StringFree( stringCache, categoryData->string );
         TA_Free( libHandle, categoryData );
         TA_TRACE_RETURN( TA_ALLOC_ERR );
      }

      /* Add it to the TA_FileIndexPriv */
      retCode = TA_ListAddTail( data->listCategory, categoryData );
      if( retCode != TA_SUCCESS )
      {
         TA_ListFree( categoryData->listSymbol );
         if( categoryData->string )
            TA_StringFree( stringCache, categoryData->string );
         TA_Free( libHandle, categoryData );
         TA_TRACE_RETURN( TA_ALLOC_ERR );
      }

      #if 0
         printf( "**ADDING CATEGORY[%s]\n", TA_StringToChar( categoryData->string ) );
      #endif
   }

   /* Return the address of the object representing that category. */
   if( added )
      *added = categoryData;


   TA_TRACE_RETURN( TA_SUCCESS );
}
示例#13
0
TA_RetCode TA_ReadOpInfoAlloc( const char *sourceInfo,
                               TA_ReadOpInfo **allocatedInfo,
                               unsigned int readOpFlags )
{
   TA_PROLOG
   TA_RetCode retCode;

   TA_ReadOp readOp;
   TA_ReadOp *arrayReadOp;
   TA_ReadOpInfo *newReadOpInfo;
   TA_Field fieldMask, fieldProvided;
   unsigned int timeframeIdx;
   unsigned int intraDayIncPeriod;
   TA_TokenId   intraDayIncToken;
   TA_TokenId   tempToken;
   unsigned int tempInt;
   unsigned int period;
   unsigned int errorOccurred;

   const char *pos;
   unsigned int inField;
   unsigned int nbField;
   unsigned int nbCharInField;
   unsigned int skipNonDigitLine;
   const char *ptrFirstCarInField;

   unsigned char localBuf[10];
   unsigned int bufIdx, opIdx, i;

   register unsigned int flagSet;
   register TA_ReadOp *ptrReadOp;
   
   TA_TRACE_BEGIN(  TA_BuildArrayReadOp );

   newReadOpInfo = (TA_ReadOpInfo *)TA_Malloc( sizeof( TA_ReadOpInfo ) );

   /* These variables are resolved within this function. */
   memset( newReadOpInfo, 0, sizeof( TA_ReadOpInfo ) );

   /* At this point, TA_ReadOpInfoFree can be safely called. */

   /* Keep track of some user provided parameter. */
   newReadOpInfo->sourceInfo = sourceInfo;
   newReadOpInfo->readOpFlags = readOpFlags;

   /* Initialize some defaults. */
   newReadOpInfo->openInterestMult = 100;
   newReadOpInfo->volumeMult       = 100;

   nbField = 0;
   intraDayIncPeriod = 0;
   intraDayIncToken = TA_TOK_END;

   pos = newReadOpInfo->sourceInfo;
   if( !pos || (*pos == '\0') )
   {
      TA_ReadOpInfoFree( newReadOpInfo );
      TA_TRACE_RETURN( TA_MISSING_FIELD );
   }

   /* Find how many fields are defined and check some syntax
    * at the same time.
    */
   if( *pos != '[' )
   {
      TA_ReadOpInfoFree( newReadOpInfo );
      TA_TRACE_RETURN( TA_INVALID_FIELD );
   }

   inField = 0;
   nbCharInField = 0;
   skipNonDigitLine = 0;
   ptrFirstCarInField = NULL;
   while( *pos != '\0' )
   {
      switch( *pos )
      {
      case '[':
         if( inField )
         {
            TA_ReadOpInfoFree( newReadOpInfo );
            TA_TRACE_RETURN( TA_INVALID_FIELD );
         }
         inField = 1;
         break;
      case ']':
         if( (!inField) || (nbCharInField == 0) )
         {
            TA_ReadOpInfoFree( newReadOpInfo );
            TA_TRACE_RETURN( TA_INVALID_FIELD );
         }

         nbField++;

         /* Exclude fields not generating a TA_ReadOp.
          * For the time being that means only the -H and -NDL field.
          */
         if( nbCharInField >= 2 )
         {
            TA_ASSERT( ptrFirstCarInField != NULL );
            if( ptrFirstCarInField[0] == '-' ) 
            {
               if( toupper(ptrFirstCarInField[1]) == 'H' )
                  nbField--;
               else if( (toupper(ptrFirstCarInField[1]) == 'N') &&
                        (toupper(ptrFirstCarInField[2]) == 'D') &&
                        (toupper(ptrFirstCarInField[3]) == 'L') )
               {
                  skipNonDigitLine = 1;
                  nbField--;
               }               
             }
         }

         inField = 0;
         nbCharInField = 0;
         ptrFirstCarInField = NULL;
         break;
      default:
         if( !inField )
         {
            TA_ReadOpInfoFree( newReadOpInfo );
            TA_TRACE_RETURN( TA_INVALID_FIELD );
         }

         if( nbCharInField == 0 )
            ptrFirstCarInField = pos;
         nbCharInField++;
         break;
      }

      pos++;
   }

   if( inField || *(pos-1) != ']' )
   {
      TA_ReadOpInfoFree( newReadOpInfo );
      TA_TRACE_RETURN( TA_INVALID_FIELD );
   }

   /* Build the TA_ReadOp array */
   arrayReadOp = (TA_ReadOp *)TA_Malloc( sizeof( TA_ReadOp ) * nbField );

   if( !arrayReadOp )
   {
      TA_ReadOpInfoFree( newReadOpInfo );
      TA_TRACE_RETURN( TA_ALLOC_ERR );
   }

   newReadOpInfo->arrayReadOp = arrayReadOp;

   pos = TA_StringToChar(newReadOpInfo->sourceInfo);

   bufIdx = 0;
   opIdx = 0;
   while( *pos != '\0' && (opIdx < nbField) )
   {
      switch( *pos )
      {
      case '[':
        break;

      case ']':
        localBuf[bufIdx] ='\0';
        bufIdx = 0;

        /* Identify the field and build the TA_ReadOp. */
        tempInt = 0;
        retCode = buildReadOp( newReadOpInfo,
                               (const char *)&localBuf[0],
                               &arrayReadOp[opIdx],
                               &tempToken, &tempInt );
        if( retCode != TA_SUCCESS )
        {
           TA_ReadOpInfoFree( newReadOpInfo );
           TA_TRACE_RETURN( retCode );
        }

        if( arrayReadOp[opIdx] != 0 )
        {
           /* Set the replace zero flag as needed */
           if( TA_IS_REPLACE_ZERO(readOpFlags) && TA_IS_REAL_CMD(arrayReadOp[opIdx]) )
           {
              TA_SET_REPLACE_ZERO(arrayReadOp[opIdx]);
           }

           /* Set the skipNonDigitLine flag as needed. */
           if( skipNonDigitLine == 1 )
           {
              TA_SET_SKIP_NDL_FLAG(arrayReadOp[opIdx]);
           }

           /* Ooof... this readOp is now all build! */
           opIdx++;
        }

        /* If this is a time token, make sure this
         * is not in contradiction with an already
         * specified increment.
         */
        if( intraDayIncPeriod )
        {
           errorOccurred = 0;
           switch( tempToken )
           {
           case TA_TOK_SEC:
           case TA_TOK_SS:
              if( (intraDayIncToken == TA_TOK_MIN) ||
                  (intraDayIncToken == TA_TOK_MN) )
                 errorOccurred = 1;
              /* no break */
           case TA_TOK_MIN:
           case TA_TOK_MN:
              if( (intraDayIncToken == TA_TOK_HOUR) ||
                  (intraDayIncToken == TA_TOK_HH) )
                 errorOccurred = 1;
              break;
           case TA_TOK_HOUR:
           case TA_TOK_HH:
              errorOccurred = 1;
              break;
           default:
              /* Do nothing */
              break;
           }

           if( errorOccurred )
           {
              TA_ReadOpInfoFree( newReadOpInfo );
              TA_TRACE_RETURN( TA_INVALID_FIELD );
           }
        }

        /* Check if a period increment is specified. */
        if( (tempInt != 0) && (tempInt != 1) )
        {
           if( intraDayIncPeriod != 0 )
           {
              TA_ReadOpInfoFree( newReadOpInfo );
              TA_TRACE_RETURN( TA_INVALID_FIELD );
           }

           intraDayIncPeriod = tempInt;
           intraDayIncToken  = tempToken;
        }
        break;

      default:
        if( bufIdx >= sizeof(localBuf)-1 )
        {
           TA_ReadOpInfoFree( newReadOpInfo );
           TA_TRACE_RETURN( TA_INVALID_FIELD );
        }

        localBuf[bufIdx++] = *pos;
        break;
      }

      pos++;
   }

   if( opIdx != nbField )
   {
      TA_ReadOpInfoFree( newReadOpInfo );
      TA_TRACE_RETURN( TA_INTERNAL_ERROR(89) );
   }

   arrayReadOp[opIdx-1] |= TA_CMD_LAST_FLAG;

   /* Build the mask representing the fields provided. */
   fieldProvided = 0;
   timeframeIdx = TA_INTEGER_ARRAY_SIZE;

   for( opIdx=0; opIdx < nbField; opIdx++ )
   {
      readOp = arrayReadOp[opIdx];

      TA_ASSERT( readOp != 0 ); /* Parano test */

      if( !TA_IS_PERMANENT_SKIP_SET(readOp) )
      {
         /* Make sure this field was not specified twice. */
         for( i=opIdx+1; i < nbField; i++ )
         {
            if( (TA_IS_REAL_CMD(readOp) && TA_IS_REAL_CMD(arrayReadOp[i])) ||
                (TA_IS_INTEGER_CMD(readOp) && TA_IS_INTEGER_CMD(arrayReadOp[i])) )
            {
               if( (TA_GET_IDX(readOp) == TA_GET_IDX(arrayReadOp[i])) &&
                   !TA_IS_PERMANENT_SKIP_SET(arrayReadOp[i]) )
               {
                  TA_ReadOpInfoFree( newReadOpInfo );
                  TA_TRACE_RETURN( TA_REDUNDANT_FIELD );
               }
            }
         }

         /* Parano test: Double-check redundant field in a different way. */
         fieldMask = TA_ReadOpToField( readOp );
         TA_ASSERT( fieldMask != 0 );
         if( !(fieldMask & TA_TIMESTAMP) && (fieldProvided & fieldMask) )
         {
            TA_ReadOpInfoFree( newReadOpInfo );
            TA_TRACE_RETURN( TA_REDUNDANT_FIELD );
         }

         /* Set the field. */
         fieldProvided |= fieldMask;

         /* Keep track of the smallest granularity of the timestamp. */
         if( fieldMask & TA_TIMESTAMP )
         {
            if( (timeframeIdx == TA_INTEGER_ARRAY_SIZE) ||
                (TA_GET_IDX(readOp) < timeframeIdx) )
               timeframeIdx = TA_GET_IDX(readOp);
         }
      }
   }


   /* No date/time reference provided!? This is considered an error
    * in the current implementation.
    */
   if( timeframeIdx == TA_INTEGER_ARRAY_SIZE )
   {
      TA_ReadOpInfoFree( newReadOpInfo );
      TA_TRACE_RETURN( TA_MISSING_DATE_OR_TIME_FIELD );
   }

   /* Determine at which point the timestamp is completed. */
   flagSet = 0;
   for( opIdx=nbField; opIdx > 0; opIdx-- )
   {
      ptrReadOp = &arrayReadOp[opIdx-1];
      readOp = *ptrReadOp;

      if( !flagSet                          && 
          TA_IS_INTEGER_CMD(readOp)         && 
          (TA_GET_IDX(readOp)<=TA_YEAR_IDX) && 
          !TA_IS_PERMANENT_SKIP_SET(readOp) )
      {
         TA_SET_TIMESTAMP_COMPLETE(*ptrReadOp);
         flagSet = 1;
      }
      else
      {
         TA_CLR_TIMESTAMP_COMPLETE(*ptrReadOp);
      }
   }

   /* Validate and identify the period. */
   period = 0;
   if( intraDayIncPeriod )
   {
      errorOccurred = 0;
      switch( timeframeIdx )
      {
      case TA_YEAR_IDX:
      case TA_MONTH_IDX:
      case TA_DAY_IDX:
         errorOccurred = 1;
         break;
      case TA_HOUR_IDX:
         if( (intraDayIncPeriod < TA_1HOUR) || (intraDayIncPeriod >= TA_DAILY) )
            errorOccurred = 1;
         break;
      case TA_MIN_IDX:
         if( (intraDayIncPeriod < TA_1MIN) || (intraDayIncPeriod >= TA_1HOUR) )
            errorOccurred = 1;
         break;
      case TA_SEC_IDX:
         if( (intraDayIncPeriod < TA_1SEC) || (intraDayIncPeriod >= TA_1MIN) )
            errorOccurred = 1;
         break;
      default:
         TA_ReadOpInfoFree( newReadOpInfo );
         TA_FATAL(  NULL, timeframeIdx, fieldProvided );
      }

      if( errorOccurred )
      {
         TA_ReadOpInfoFree( newReadOpInfo );
         TA_TRACE_RETURN( TA_INVALID_FIELD );
      }
            
      period = intraDayIncPeriod;
   }
   else
   {
      switch( timeframeIdx )
      {
      case TA_YEAR_IDX:
         period = TA_YEARLY;
         break;
      case TA_MONTH_IDX:
         period = TA_MONTHLY;
         break;
      case TA_DAY_IDX:
         period = TA_DAILY;
         break;
      case TA_HOUR_IDX:
         period = TA_1HOUR;
         break;
      case TA_MIN_IDX:
         period = TA_1MIN;
         break;
      case TA_SEC_IDX:
         period = TA_1SEC;
         break;
      default:
         TA_FATAL(  NULL, timeframeIdx, fieldProvided );
      }
   }

   /* A last check... */
   if( period == 0 )
   {
      TA_ReadOpInfoFree( newReadOpInfo );
      TA_TRACE_RETURN( TA_INVALID_FIELD );
   }
         
   /* Everything is fine, let's return the information. */
   newReadOpInfo->arrayReadOp = arrayReadOp;
   newReadOpInfo->fieldProvided = fieldProvided;
   newReadOpInfo->nbReadOp = nbField;
   newReadOpInfo->period = period;

   *allocatedInfo = newReadOpInfo;

   TA_TRACE_RETURN( TA_SUCCESS );
}
示例#14
0
/**** Local functions definitions.     ****/
static TA_RetCode translateToYahooName( TA_Libc *libHandle,
                                        const TA_String *categoryName,
                                        const TA_String *symbolName,
                                        char *buffer,
                                        unsigned int maxBufferSize )
{
   TA_CountryId countryId;
   unsigned int i, symbolLength, xchangeLength, extLength, typeLength;
   const char *symbol;
   const char *xchange;
   const char *type;
   const char *category;
   const char *ext;

   (void)libHandle;

   category = TA_StringToChar(categoryName);

   /* Identify the symbol and its length. */
   symbol = TA_StringToChar(symbolName);

   symbolLength = strlen( symbol );
   if( symbolLength >= maxBufferSize )
      return TA_INVALID_SECURITY_SYMBOL;

   strcpy( buffer, symbol );

   /* Trap special case where the symbol/category is for
    * one of the hard coded indice.
    */

   for( i=0; i < hardCodedIndiceSize; i++ )
   {
      if( (strcmp( hardCodedIndice[i].symbolLib, TA_StringToChar( symbolName ) ) == 0) &&
          (strcmp( hardCodedIndice[i].categoryLib, TA_StringToChar( categoryName ) ) == 0) )
      {
         strncpy( buffer, hardCodedIndice[i].symbolYahoo, maxBufferSize );
         return TA_SUCCESS;
      }
   }

   /* Identify if an extenstion must be appended
    * to the symbol.
    * At the same time, verify the country. 
    */
   countryId = TA_CountryAbbrevToId( TA_StringToChar(categoryName) );
   switch( countryId )
   {
   case TA_Country_ID_CA: /* Canada */
   case TA_Country_ID_US: /* United States */
   case TA_Country_ID_UK: /* United Kingdom */
   case TA_Country_ID_DE: /* Germany */
   case TA_Country_ID_DK: /* Denmark */
   case TA_Country_ID_ES: /* Spain */
   case TA_Country_ID_FR: /* France */
   case TA_Country_ID_IT: /* Italy */
   case TA_Country_ID_SE: /* Sweden */
   case TA_Country_ID_NO: /* Norway */
      /* Get the length of the second field of the category.
       * This field must exist, else an error is returned.
       */
      xchangeLength = getstrfldlen( category, 1, 0, "." ) -1;
      if( xchangeLength < 2 )
         return TA_INVALID_SECURITY_EXCHANGE;
      xchange = strchr( category, '.' );
      if( !xchange || (*xchange == '\0') )
         return TA_INVALID_SECURITY_EXCHANGE;
      xchange++;
      if( *xchange == '\0' )
         return TA_INVALID_SECURITY_EXCHANGE;

      /* Get the length of the third field of the category.
       * This field must exist, else an error is returned.
       */
      type = strchr( xchange, '.' );
      if( !type || (type == xchange) || (*type == '\0') )
         return TA_INVALID_SECURITY_TYPE;
      type++;
      if( *type == '\0' )
         return TA_INVALID_SECURITY_TYPE;
      typeLength = strlen( type );

      /* Look for the possible extension corresponding to
       * this exchange. If found, append it to the symbol.
       */
      for( i=0; i < NB_YAHOO_EXCHANGE_EXTENSION; i++ )
      {         
         if( (TA_YahooExtensionTable[i].countryId == countryId) &&
             (lexncmp( TA_YahooExtensionTable[i].exchange, xchange, xchangeLength ) == 0) &&
             (lexncmp( TA_YahooExtensionTable[i].type, type, typeLength ) == 0) )
         {
            ext = TA_YahooExtensionTable[i].extension;
            extLength = strlen( ext );
            if( extLength+symbolLength+1 > maxBufferSize-1 )
               return TA_INVALID_SECURITY_EXCHANGE;
            buffer[symbolLength] = '.';
            symbolLength++;
            strcpy( &buffer[symbolLength], ext );
            break; /* Exit the loop */
         }
      }
      break;
   default:
      return TA_INVALID_SECURITY_COUNTRY;
   }

   /* At this point, buffer contains the name as used by Yahoo! web site. */

   return TA_SUCCESS;
}