Beispiel #1
0
static void buildUIRSuffix( const UIRSuffixParsing *parsedString,
                            TA_Timestamp *startTimestamp,
                            TA_Timestamp *endTimestamp,
                            char *output )
{  
   int i;

   strncpy( output, parsedString->part1, parsedString->part1Length );
   i = parsedString->part1Length;

   sprintf( output,
            "&a=%02d&b=%02d&c=%04d",
            TA_GetMonth( startTimestamp )-1, /* Yahoo! month is zero base */
            TA_GetDay( startTimestamp ),
            TA_GetYear( startTimestamp ) );
   i += 17;

   strncpy( &output[i], parsedString->part2, parsedString->part2Length );
   i += parsedString->part2Length;

   sprintf( &output[i],
            "&d=%02d&e=%02d&f=%04d",
            TA_GetMonth( endTimestamp )-1, /* Yahoo! month is zero base */
            TA_GetDay( endTimestamp ),
            TA_GetYear( endTimestamp ) );
   i += 17;

   strncpy( &output[i], parsedString->part3, parsedString->part3Length );
   i += parsedString->part3Length;

   output[i] = '\0';

   #if DEBUG_PRINTF
   printf( "New UIR=[%s]\n", output );
   #endif
}
Beispiel #2
0
TA_RetCode TA_ReadOp_Do( TA_FileHandle       *fileHandle,
                         const TA_ReadOpInfo *readOpInfo,
                         TA_Period            period,
                         const TA_Timestamp  *start,
                         const TA_Timestamp  *end,
                         unsigned int         minimumNbBar,
                         TA_Field             fieldToAlloc,
                         TA_ParamForAddData  *paramForAddData,
                         unsigned int        *nbBarAdded )
{
   TA_PROLOG
   TA_RetCode retCode;
   TA_EstimateInfo estimationInfo;

   unsigned int nbElementToAllocate;
   unsigned int memoryNeeded; /* Boolean */
   unsigned int timeNeeded;   /* Boolean */

   TA_Real    *arrayReal[TA_REAL_ARRAY_SIZE];
   TA_Integer *arrayInteger[TA_INTEGER_ARRAY_SIZE];
   TA_Timestamp *timestamp;

   TA_Real *openBeg, *highBeg, *lowBeg, *closeBeg;
   TA_Integer *volumeBeg, *openInterestBeg;
   TA_Timestamp *timestampBeg;
   TA_Timestamp tmpTimestamp;

   TA_ReadOp op;

   TA_Field fieldToProcess;
   unsigned int year, month, day, hour, min, sec;
   TA_Integer curOp;

   unsigned int nbTotalByteDone, nbTotalBarDone;
   unsigned int nbBarAddedInTheBlock;

   char monthChar[4];
   char cnvtArray[CNVT_ARRAY_SIZE];
   unsigned int  cnvtArrayIdx;

   unsigned int nbByteToAllocReal;
   unsigned int nbByteToAllocInteger;

   unsigned int fileSize;
   unsigned int skipField;
   unsigned int lineToSkip;

   unsigned int nbByteRead;
   unsigned int nbLetter;

   TA_Real lastValidClose;

   const char *car;

   register TA_Real tmpReal;
   register TA_Integer tmpInt;
   register unsigned int tmpIdx;
   register unsigned int nbCharToRead;

   unsigned int lastOpFieldIncremented;
   TA_TRACE_BEGIN( TA_PriceBarRead );

   /* Initialization of local variables. */
   openBeg = highBeg = lowBeg = closeBeg = NULL;
   timestampBeg = NULL;
   volumeBeg = openInterestBeg = NULL;
   timestamp = NULL;
   retCode = TA_SUCCESS;
   lastValidClose = 0.0;

   fieldToProcess = readOpInfo->fieldProvided & fieldToAlloc;
   if( (fieldToProcess & fieldToAlloc) != fieldToAlloc )
   {
      /* Nothing to read because not all the requested
       * fields are provided by this data source!
       */
      return TA_SUCCESS;
   }

   /* Estimate the initial amount of memory to allocate. */
   fileSize = TA_FileSize( fileHandle );
   retCode = TA_EstimateAllocInit( start, end, period,                                   
                                   minimumNbBar, 2048,
                                   &estimationInfo,
                                   &nbElementToAllocate );
   if( retCode != TA_SUCCESS )
   {
      TA_TRACE_RETURN( retCode );
   }

   if( nbElementToAllocate == 0 )
   {
      TA_TRACE_RETURN( TA_SUCCESS ); /* Nothing to read!? Just return... */
   }

   memset( arrayInteger, 0, sizeof( arrayInteger ) );
   memset( arrayReal,    0, sizeof( arrayReal ) );

   /* Set the date/time pointers to where the information will be stored. */
   arrayInteger[TA_HOUR_IDX]  = (TA_Integer *)&hour;
   arrayInteger[TA_MIN_IDX]   = (TA_Integer *)&min;
   arrayInteger[TA_SEC_IDX]   = (TA_Integer *)&sec;
   arrayInteger[TA_MONTH_IDX] = (TA_Integer *)&month;
   arrayInteger[TA_YEAR_IDX]  = (TA_Integer *)&year;
   arrayInteger[TA_DAY_IDX]   = (TA_Integer *)&day;

   /* Set default time/date. */
   year  = 1900;
   month = day = 1;
   hour  = 23;
   min   = sec = 59;

   /* Check if the processing of the time will be needed. */
   timeNeeded = isTimeNeeded( readOpInfo->arrayReadOp);

   /* 'car' always point to the character being currently handled. */
   nbByteRead = 0;
   car = TA_FileSeqRead( fileHandle, &nbByteRead );
   if( (car == NULL) || (nbByteRead == 0) )
      return TA_SUCCESS; /* End of file! */
   --nbByteRead;

   nbTotalByteDone = 0;
   nbTotalBarDone  = 0;
   nbBarAddedInTheBlock = 0;
   memoryNeeded    = 1;
   curOp           = 0;
   skipField       = 0;

   monthChar[3] = '\0';

   /* When requested, skip header lines. */
   lineToSkip = readOpInfo->nbHeaderLineToSkip;
   while( lineToSkip-- )
   {
      while( *car != '\n' )
      {
         GET_CHAR;
         if( car == NULL )
            goto exit_loops;
      }
   }

line_loop: /* Always jump here when end-of-line is found (EOL). */

      /* If curOp != 0, the last operations are canceled. */
      REVERT_OPERATIONS;
      curOp = 0;
      lastOpFieldIncremented = 0;

      /* Start over a new line. */

      if( memoryNeeded )
      {
         /* Allocate the memory. */
         nbByteToAllocReal = nbElementToAllocate * sizeof( TA_Real );
         nbByteToAllocInteger = nbElementToAllocate * sizeof( TA_Integer );

         timestamp = (TA_Timestamp *)TA_Malloc( nbElementToAllocate * sizeof( TA_Timestamp ) );
         timestampBeg = timestamp;

         if( !timestampBeg )
         {
            retCode = TA_ALLOC_ERR;
            goto exit_loops;
         }

         #define TA_ALLOC_MEM(upperc,lowerc,typepar) \
         { \
            if( fieldToProcess & TA_##upperc ) \
            { \
               lowerc##Beg = (TA_##typepar *)TA_Malloc( nbByteToAlloc##typepar ); \
               array##typepar[TA_##upperc##_IDX] = lowerc##Beg; \
               if( !lowerc##Beg ) \
               { \
                  retCode = TA_ALLOC_ERR; \
                  goto exit_loops; \
               } \
            } \
         }
         TA_ALLOC_MEM( OPEN,  open,  Real );
         TA_ALLOC_MEM( HIGH,  high,  Real );
         TA_ALLOC_MEM( LOW,   low,   Real );
         TA_ALLOC_MEM( CLOSE, close, Real );

         TA_ALLOC_MEM( VOLUME, volume, Integer );
         TA_ALLOC_MEM( OPENINTEREST, openInterest, Integer );
         #undef TA_ALLOC_MEM

         memoryNeeded = 0;
      }

op_loop: /* Jump here when ready to proceed with the next command. */

      op = readOpInfo->arrayReadOp[curOp];

      if( !(op&TA_CMD_READ_MONTH_CHAR) )
      {
         /* Skip leading non-numeric character. */
         SKIP_UNTIL_NUMERIC;
      }

      /* Shall we skip this field? */
      if( TA_IS_SKIP_SET(op) )
      {
         if( (op&(TA_CMD_READ_REAL|TA_CMD_READ_INTEGER)) == 0 )
         {
            tmpInt = TA_GET_NB_NUMERIC(op);
            curOp++;
            while( tmpInt-- )
            {
               GET_CHAR;
               CHECK_EOL_EOF;
            }
         }
         else
         {
            if( skipField == 0 )
            {
               skipField = TA_GET_NB_NUMERIC(op);
               TA_ASSERT( skipField > 0 );
            }

            if( --skipField == 0 )
               curOp++;

            SKIP_NUMERIC;
            if( (op&TA_CMD_READ_REAL) && (*car == '.') )
            {
               GET_CHAR;
               CHECK_EOL_EOF;
               SKIP_NUMERIC;
            }
         }
      }
      else
      {
         cnvtArrayIdx = 0;

         if( TA_IS_REAL_CMD(op) )
         {
            /* Extract a numeric into cnvtArray. */
            READ_IN_CNVT_ARRAY;

            /* This is a TA_Real. */
            if( car && (*car == '.') )
            {
               /* Read rest of the float after the '.' */
               READ_IN_CNVT_ARRAY;
            }
            cnvtArray[cnvtArrayIdx] = '\0';
            tmpReal = atof( &cnvtArray[0] );

            /* Write the TA_Real in memory. */
            tmpIdx = TA_GET_IDX(op);
            TA_ASSERT( tmpIdx < TA_REAL_ARRAY_SIZE );
            TA_ASSERT( arrayReal[tmpIdx] != NULL );
            if( tmpReal != 0.0 )
            {
               *(arrayReal[tmpIdx]) = tmpReal;
               if( tmpIdx == TA_CLOSE_IDX )
                  lastValidClose = tmpReal;
            }
            else if( TA_IS_REPLACE_ZERO(op) )
            {
               /* Replace this zero value with the last known close.
                * If there is no previous close, this line is ignored.
                */
               if( lastValidClose != 0.0 )
                  *(arrayReal[tmpIdx]) = lastValidClose;
               else
               {
                  SKIP_LINE;
               }
            }
            else
            {
               /* Zero are not expected, consider this as a failure
                * and ignore all further data from this file.
                */
               retCode = TA_PRICE_BAR_CONTAINS_ZERO;
               goto exit_loops;
            }

            arrayReal[tmpIdx]++;
            curOp++;
         }
         else
         {
            /* This is a TA_Integer. */
            if( !(op&TA_CMD_READ_MONTH_CHAR) )
            {
               nbCharToRead = TA_GET_NB_NUMERIC(op);
               if( nbCharToRead )
               {
                  READ_N_CHAR_IN_CNVT_ARRAY(nbCharToRead);
               }
               else
               {
                  READ_IN_CNVT_ARRAY;
               }

               cnvtArray[cnvtArrayIdx] = '\0';
               tmpInt = atoi( &cnvtArray[0] );
            }
            else
            {
               /* Try to find a 3 letters month string. 
                * Translate it to a [1..12] integer.
                */
               nbLetter = 1;
               do
               {
                  CHECK_EOL_EOF;
                  monthChar[nbLetter] = (char)toupper(*car);
                  GET_CHAR;
                  nbLetter++;
               } while( nbLetter != 3 );
               
               do
               {
                  CHECK_EOL_EOF;
                  monthChar[0] = monthChar[1];
                  monthChar[1] = monthChar[2];
                  monthChar[2] = (char)toupper(*car);
                  if( strncmp("JAN",monthChar,3) == 0 )
                     tmpInt = 1;
                  else if( strncmp("FEB",monthChar,3) == 0 )
                     tmpInt = 2;
                  else if( strncmp("MAR",monthChar,3) == 0 )
                     tmpInt = 3;
                  else if( strncmp("APR",monthChar,3) == 0 )
                     tmpInt = 4;
                  else if( strncmp("MAY",monthChar,3) == 0 )
                     tmpInt = 5;
                  else if( strncmp("JUN",monthChar,3) == 0 )
                     tmpInt = 6;
                  else if( strncmp("JUL",monthChar,3) == 0 )
                     tmpInt = 7;
                  else if( strncmp("AUG",monthChar,3) == 0 )
                     tmpInt = 8;
                  else if( strncmp("SEP",monthChar,3) == 0 )
                     tmpInt = 9;
                  else if( strncmp("OCT",monthChar,3) == 0 )
                     tmpInt = 10;
                  else if( strncmp("NOV",monthChar,3) == 0 )
                     tmpInt = 11;
                  else if( strncmp("DEC",monthChar,3) == 0 )
                     tmpInt = 12;
                  else
                     tmpInt = 0;

                  GET_CHAR;
               } while( tmpInt == 0 );
            }

            /* Write the TA_Integer in memory. */
            tmpIdx = TA_GET_IDX(op);
            TA_ASSERT( tmpIdx < TA_INTEGER_ARRAY_SIZE );
            TA_ASSERT( arrayInteger[tmpIdx] != NULL );
            *(arrayInteger[tmpIdx]) = tmpInt;

            if( tmpIdx > TA_YEAR_IDX )
               arrayInteger[tmpIdx]++;
            curOp++;

            if( TA_IS_TIMESTAMP_COMPLETE(op) )
            {
               /* Build the timestamp. */
               retCode = TA_SetDate( year, month, day, &tmpTimestamp );
               if( retCode != TA_SUCCESS )
                  goto exit_loops; /* Invalid date */

               if( !timeNeeded )
               {
                  /* Ignore time in comparison and use default to build the price bar. */
                  tmpTimestamp.time = 23595900; /* Default EOD time */
                  if( start && (tmpTimestamp.date < start->date) )
                  {
                     /* This price bar is not needed, jump to the next line. */
                     retCode = TA_SUCCESS;
                     SKIP_LINE;
                  }

                  if( end && (tmpTimestamp.date > end->date) )
                  {
                     /* This price bar is beyond the upper limit, just exit. */
                     goto exit_loops;
                  }
               }
               else
               {
                  retCode = TA_SetTime( hour, min, sec, &tmpTimestamp );
                  if( retCode != TA_SUCCESS )
                     goto exit_loops; /* Invalid time */
                  if( start && TA_TimestampLess(&tmpTimestamp,start) )
                  {
                     /* This price bar is not needed, jump to the next line. */
                     retCode = TA_SUCCESS;
                     SKIP_LINE;
                  }

                  if( end && TA_TimestampGreater(&tmpTimestamp, end) )
                  {
                     /* This price bar is beyond the upper limit, just exit. */
                     goto exit_loops;
                  }
               }

               /* Write the timestamp in memory. */
               *timestamp = tmpTimestamp;
            }
         }

         if( TA_IS_READ_STOP_FLAG_SET(op) )
         {
            #ifdef DEBUG_PRINTF
               printf( "(%d%d%d,%e,%e,%e,%e,%d)\n",
                  timestampBeg?TA_GetYear(&timestampBeg[nbBarAddedInTheBlock]):0,
                  timestampBeg?TA_GetMonth(&timestampBeg[nbBarAddedInTheBlock]):0,
                  timestampBeg?TA_GetDay(&timestampBeg[nbBarAddedInTheBlock]):0,
                  openBeg?openBeg[nbBarAddedInTheBlock]:0.0,
                  highBeg?highBeg[nbBarAddedInTheBlock]:0.0,
                  lowBeg?lowBeg[nbBarAddedInTheBlock]:0.0,
                  closeBeg?closeBeg[nbBarAddedInTheBlock]:0.0,
                  volumeBeg?volumeBeg[nbBarAddedInTheBlock]:0 );
            #endif

            /* At this point, the price bar is completely written in memory. */
            timestamp++;
            curOp = 0;
            nbBarAddedInTheBlock++;
            if( nbBarAddedInTheBlock < nbElementToAllocate )
            {
              /* Go to next line. */
              SKIP_LINE;
            }
            else
            {
               /* There is not enough memory for another bar, so re-allocate
                * some more.
                */
               retCode = TA_HistoryAddData( paramForAddData, nbBarAddedInTheBlock,
                                            period, timestampBeg,
                                            openBeg, highBeg, lowBeg, closeBeg,
                                            volumeBeg, openInterestBeg );

               /* TA_HistoryAddData is ALWAYS the owner of these memory block
                * when called. So we set these to NULL to make sure there will
                * be no attempt to free these from this function.
                */
               openBeg = highBeg = lowBeg = closeBeg = NULL;
               timestampBeg = NULL;
               volumeBeg = openInterestBeg = NULL;
               nbTotalBarDone += nbBarAddedInTheBlock;
               nbBarAddedInTheBlock = 0;

               if( retCode != TA_SUCCESS )
                  goto exit_loops;

               retCode = TA_EstimateAllocNext( &estimationInfo, &nbElementToAllocate );
               if( retCode != TA_SUCCESS )
                  goto exit_loops;

               memoryNeeded = 1;
               SKIP_LINE;
            }
         }
         else
         {
            /* Make sure we did not hit an EOL or EOF prematurly, if yes,
             * this line will be silently ignored.
             */
            CHECK_EOL_EOF;
         }
      }

      goto op_loop;

exit_loops: /* Jump here when the end-of-file is hit (or an error occured) */

   /* On succesful exit, process possibly remaining data. */
   if( (retCode == TA_SUCCESS) && (nbBarAddedInTheBlock != 0) )
   {
      retCode = TA_HistoryAddData( paramForAddData, nbBarAddedInTheBlock,
                                   period, timestampBeg,
                                   openBeg, highBeg, lowBeg, closeBeg,
                                   volumeBeg, openInterestBeg );

      openBeg = highBeg = lowBeg = closeBeg = NULL;
      timestampBeg = NULL;
      volumeBeg = openInterestBeg = NULL;
      nbTotalBarDone += nbBarAddedInTheBlock;
   }
   
   /* ALWAYS verify if locally allocated memory needs to be freed. ALWAYS. */
   FREE_IF_NOT_NULL( openBeg );
   FREE_IF_NOT_NULL( highBeg );
   FREE_IF_NOT_NULL( lowBeg );
   FREE_IF_NOT_NULL( closeBeg );
   FREE_IF_NOT_NULL( volumeBeg );
   FREE_IF_NOT_NULL( openInterestBeg );
   FREE_IF_NOT_NULL( timestampBeg );

   /* An indication that no more data needs to be provided is not a failure. */
   if( retCode == TA_ENOUGH_DATA )
      retCode = TA_SUCCESS;

   /* Return the number of added price bar to the caller. */
   if( nbBarAdded )
      *nbBarAdded = nbTotalBarDone;

   TA_TRACE_RETURN( retCode );
}
Beispiel #3
0
TA_RetCode TA_TradeReportToFile( TA_TradeReport *tradeReport, FILE *out )
{
    TA_TradeReportPriv *tradeReportPriv;
    const TA_Timestamp *entryTimestamp;
    const TA_Timestamp *exitTimestamp;
    unsigned int i;
    double tmpReal;

    if( !tradeReport || !out )
        return TA_BAD_PARAM;

    /* Make sure this TA_TradeReport is a valid object */
    tradeReportPriv = (TA_TradeReportPriv *)tradeReport->hiddenData;
    if( !tradeReportPriv || (tradeReportPriv->magicNb != TA_TRADEREPORT_MAGIC_NB) )
        return TA_BAD_OBJECT;

    fprintf( out, "\n" );
    fprintf( out, "[MM/DD/YYYY HH:MM:SS .. MM/DD/YYYY HH:MM:SS] [ID]\n" );
    fprintf( out, "  Quantity  Entry($) Profit(%%)  MinFE(%%)  MaxFE(%%)    MAE(%%)\n" );
    fprintf( out, "============================================================\n" );

    for( i=0; i < tradeReport->nbTrades; i++ )
    {
        entryTimestamp = &tradeReport->trades[i]->entryTimestamp;
        exitTimestamp  = &tradeReport->trades[i]->exitTimestamp;

        fprintf( out, "[%02d/%02d/%04d %02d:%02d:%02d .. %02d/%02d/%04d %02d:%02d:%02d] [%s]\n",
                 TA_GetMonth(entryTimestamp),
                 TA_GetDay  (entryTimestamp),
                 TA_GetYear (entryTimestamp),
                 TA_GetHour (entryTimestamp),
                 TA_GetMin  (entryTimestamp),
                 TA_GetSec  (entryTimestamp),
                 TA_GetMonth(exitTimestamp),
                 TA_GetDay  (exitTimestamp),
                 TA_GetYear (exitTimestamp),
                 TA_GetHour (exitTimestamp),
                 TA_GetMin  (exitTimestamp),
                 TA_GetSec  (exitTimestamp),
                 tradeReport->trades[i]->id->symString );

        fprintf( out, "%10d",   tradeReport->trades[i]->quantity );
        fprintf( out, "%10.2f", tradeReport->trades[i]->entryPrice );
        fprintf( out, "%10.2f", tradeReport->trades[i]->profit );

        tmpReal = tradeReport->trades[i]->minfe;
        if( tmpReal != TA_REAL_DEFAULT )
            fprintf( out, "%10.2f", tmpReal );
        else
            fprintf( out, "%10s", "N/A" );

        tmpReal = tradeReport->trades[i]->maxfe;
        if( tmpReal != TA_REAL_DEFAULT )
            fprintf( out, "%10.2f", tmpReal );
        else
            fprintf( out, "%10s", "N/A" );

        tmpReal = tradeReport->trades[i]->mae;
        if( tmpReal != TA_REAL_DEFAULT )
            fprintf( out, "%10.2f", tmpReal );
        else
            fprintf( out, "%10s", "N/A" );

        fprintf( out, "\n\n" );
    }

    return TA_SUCCESS;
}
Beispiel #4
0
/**** Global functions definitions.   ****/
TA_RetCode TA_GetHistoryDataFromWeb( 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;
   TA_DecodingParam directYahooDecodingParam;
   const TA_DecodingParam *decodingParam;
   TA_FileHandle *fileHandle;
   TA_ReadOpInfo *readOpInfo;
   TA_UIRSuffixParsing suffixParsing;
   TA_Timestamp firstBarTimestamp, lastBarTimestamp, prevEndDate;
   TA_InfoFromAddedData infoFromAddedData;
   TA_DayOfWeek dayOfWeek;
   TA_Timestamp curAdjustYear, lastAdjustYear;  
   const char *overideServerAddr;

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

   TA_TRACE_BEGIN( TA_GetHistoryDataFromWeb );

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

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

   retCode = TA_BAD_PARAM;

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

   if( end )
      TA_TimestampCopy( &lastBarTimestamp, end );
   else
      TA_SetDateNow( &lastBarTimestamp );

   /* Time component is not important for Yahoo! but all end of day
    * price bar use 00:00:00, so do the same here.
    */
   TA_SetTime( 0, 0, 0, &firstBarTimestamp );
   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 );

   TA_ASSERT( yahooHandle != NULL );

   if( yahooHandle->param->id == TA_YAHOO_ONE_SYMBOL )
   {
      /* User specified Yahoo! name. */
      yahooName = TA_StringDup(stringCache,yahooHandle->webSiteSymbol);
      TA_ASSERT( yahooName != NULL );
   }
   else
   {
      /* Map the TA-Lib name into the Yahoo! name. */
      retCode = TA_AllocStringFromLibName( categoryHandle->string,
                                           symbolHandle->string,
                                           &yahooName );  
      if( retCode != TA_SUCCESS )
      {
         TA_TRACE_RETURN( retCode );
      }

      TA_ASSERT( yahooName != NULL );
   }

   /* Check if the user did overide the server address in the location parameter. 
    * (as needed, convert from TA_String to char *)
    */
   if( yahooHandle->userSpecifiedServer )
      overideServerAddr = TA_StringToChar(yahooHandle->userSpecifiedServer);
   else
      overideServerAddr = NULL;
   
   /* Get the decoding parameter for the CSV web page. */
   if( yahooHandle->param->id == TA_YAHOO_ONE_SYMBOL )
   {
      retCode = TA_YahooIdxDataDecoding( yahooHandle->webSiteCountry,
                                         TA_YAHOOIDX_CSV_PAGE,
                                         &directYahooDecodingParam );
      if( retCode != TA_SUCCESS )
      {
         TA_StringFree( stringCache, yahooName );
         TA_TRACE_RETURN( retCode );
      }
      decodingParam = &directYahooDecodingParam;
   }
   else
   {
      decodingParam = TA_YahooIdxDecodingParam( yahooHandle->index, TA_YAHOOIDX_CSV_PAGE );
      if( !decodingParam )
      {
         TA_StringFree( stringCache, yahooName );
         TA_TRACE_RETURN( TA_INTERNAL_ERROR(103) );
      }
   }

   localDecodingParam = *decodingParam;

   /* Check if split/value adjustment are necessary. */
   if( (yahooHandle->param->flags & TA_DO_NOT_SPLIT_ADJUST) &&
       (yahooHandle->param->flags & TA_DO_NOT_VALUE_ADJUST) )
   {
      doAdjustment = 0;
   }
   else
      doAdjustment = 1;


   /* 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) );
   }

   /* 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).
    */

   /* Replace the uirSuffix with a large local buffer. */
   localDecodingParam.uirSuffix = TA_Malloc( 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) )
   {    
      retCode = TA_DriverShouldContinue(paramForAddData);
      if( retCode != TA_SUCCESS )
      {
         TA_StringFree( stringCache, yahooName );
         TA_Free( (char *)localDecodingParam.uirSuffix );
         #if !defined( TA_SINGLE_THREAD )   
            if( readOpInfo )
               TA_ReadOpInfoFree( readOpInfo );
         #endif
         TA_TRACE_RETURN( retCode );
      }

      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( &localDecodingParam,
                                              TA_StringToChar(yahooName),
                                              overideServerAddr,
                                              &webPage, paramForAddData );
           
      if( retCode != TA_SUCCESS )
      {
         TA_StringFree( stringCache, yahooName );
         TA_Free( (char *)localDecodingParam.uirSuffix );
         #if !defined( TA_SINGLE_THREAD )   
            if( readOpInfo )
               TA_ReadOpInfoFree( readOpInfo );
         #endif
         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( webPage->content, &fileHandle );
      if( retCode != TA_SUCCESS )
      {
         /* Clean-up and exit */
         TA_StringFree( stringCache, yahooName );
         TA_WebPageFree( webPage );
         TA_Free( (char *)localDecodingParam.uirSuffix );
         #if !defined( TA_SINGLE_THREAD )   
            if( readOpInfo )
               TA_ReadOpInfoFree( readOpInfo );
         #endif
         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;
         }

         #if !defined( TA_SINGLE_THREAD )   
            /* Must use a local copy if multi-threaded */
            retCode = TA_ReadOpInfoClone(&readOpInfo, readOpInfo);
            if( retCode != TA_SUCCESS )
            {
               /* Clean-up and exit */
               TA_StringFree( stringCache, yahooName );
               TA_WebPageFree( webPage );
               TA_Free( (char *)localDecodingParam.uirSuffix );
               TA_TRACE_RETURN( retCode );
            }
         #endif

         /* 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( readOpInfo,
                                       period,
                                       fieldToAlloc );
         if( retCode != TA_SUCCESS )
         {
            /* Clean-up and exit */
            TA_StringFree( stringCache, yahooName );
            TA_WebPageFree( webPage );
            TA_Free( (char *)localDecodingParam.uirSuffix );
            #if !defined( TA_SINGLE_THREAD )   
               if( readOpInfo )
                  TA_ReadOpInfoFree( readOpInfo );
            #endif
            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( fileHandle,                           
                              readOpInfo,
                              period, &firstBarTimestamp, &lastBarTimestamp,
                              nbEstimateBar, fieldToAlloc,
                              paramForAddData,
                              &nbBarAdded );

      TA_FileSeqClose( fileHandle );
      TA_WebPageFree( webPage );

      nbTotalBarAdded += nbBarAdded;

      if( retCode != TA_SUCCESS )
      {
         /* Clean-up and exit */
         TA_StringFree( stringCache, yahooName );
         TA_Free( (char *)localDecodingParam.uirSuffix );
         #if !defined( TA_SINGLE_THREAD )   
            if( readOpInfo )
               TA_ReadOpInfoFree( readOpInfo );
         #endif
         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( (char *)localDecodingParam.uirSuffix );
            #if !defined( TA_SINGLE_THREAD )   
               if( readOpInfo )
                  TA_ReadOpInfoFree( readOpInfo );
            #endif
            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( (char *)localDecodingParam.uirSuffix );
            TA_StringFree( stringCache, yahooName );
            #if !defined( TA_SINGLE_THREAD )   
               if( readOpInfo )
                  TA_ReadOpInfoFree( readOpInfo );
            #endif
            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;
   }

   /* Get rid of some memory not used anymore. */
   TA_Free( (char *)localDecodingParam.uirSuffix );
   #if !defined( TA_SINGLE_THREAD )   
      if( readOpInfo )
         TA_ReadOpInfoFree( readOpInfo );
   #endif

   /* If adjusted data is requested, use splits and dividend info from Yahoo!. */
   if( doAdjustment && (nbTotalBarAdded >= 1) )
   {
      /* Get the decoding parameter for the adjustment page. */
      if( yahooHandle->param->id == TA_YAHOO_ONE_SYMBOL )
      {
         retCode = TA_YahooIdxDataDecoding( yahooHandle->webSiteCountry,
                                            TA_YAHOOIDX_ADJUSTMENT,
                                            &directYahooDecodingParam );
         if( retCode != TA_SUCCESS )
         {
            TA_StringFree( stringCache, yahooName );
            TA_TRACE_RETURN( retCode );
         }
         decodingParam = &directYahooDecodingParam;
      }
      else
      {
         decodingParam = TA_YahooIdxDecodingParam( yahooHandle->index, TA_YAHOOIDX_ADJUSTMENT );
         if( !decodingParam )
         {
            TA_StringFree( stringCache, yahooName );
            TA_TRACE_RETURN( TA_INTERNAL_ERROR(140) );
         }
      }
      localDecodingParam = *decodingParam;

      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(141) );
      }

      /* 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).
       */

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


      /* curAdjustYear indicates for which year the download is
       * taking place.
       */
      TA_SetDefault( &curAdjustYear );
      TA_SetDateNow( &curAdjustYear );

      /* Identify the oldest year for which data was downloaded */
      TA_GetInfoFromAddedData( paramForAddData, &infoFromAddedData );
      TA_TimestampCopy( &lastAdjustYear, &infoFromAddedData.lowestTimestamp );
      TA_PrevYear( &lastAdjustYear ); /* Get one more year to be on the safe side. */

      while( TA_TimestampLess( &lastAdjustYear, &curAdjustYear ) )
      {
         /* Set prevEndDate to two years earlier. */
         TA_TimestampCopy( &prevEndDate, &curAdjustYear );
         TA_PrevYear( &prevEndDate );
         TA_PrevYear( &prevEndDate );
         
         /* Change the dates in the uirSuffix. */
         TA_SetDate( TA_GetYear(&curAdjustYear), 12, 31, &curAdjustYear );
         TA_SetDate( TA_GetYear(&prevEndDate), 1, 1, &prevEndDate );
         buildUIRSuffix( &suffixParsing,
                         &prevEndDate, &curAdjustYear,
                         (char *)localDecodingParam.uirSuffix );

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

         /* Move 3 years earlier. */
         TA_PrevYear( &prevEndDate );
         TA_TimestampCopy( &curAdjustYear, &prevEndDate );
      }

      /* Clean-up what was allocated for the adjustment logic. */
      TA_Free( (char *)localDecodingParam.uirSuffix );
   }

   /* Clean-up and exit */
   TA_StringFree( stringCache, yahooName );
   TA_TRACE_RETURN( retCode );
}
Beispiel #5
0
/**** Local functions definitions.     ****/
ErrorNumber test_period( TA_UDBase *unifiedDatabase )
{
   TA_RetCode retCode;
   TA_History *history;
   const TA_Timestamp *timestamp;
   unsigned int i;
   ErrorNumber retValue;
   TA_AddDataSourceParam addParam;
   TA_HistoryAllocParam histParam;

   printf( "Testing period/timeframe conversion\n" );

   /* Add access to some intra-day data. */
   memset( &addParam, 0, sizeof( TA_AddDataSourceParam) );
   addParam.id = TA_ASCII_FILE;
   addParam.location = "..\\src\\tools\\ta_regtest\\sampling\\ES.csv";
   addParam.info ="[YY][MM][DD][HH][MN=5][O][H][L][C][V]";
   addParam.category = "TA_SIM_REF";
   retCode = TA_AddDataSource( unifiedDatabase,&addParam );
   if( retCode != TA_SUCCESS )
   {
      printf( "Can't access [%s] (%d)\n", addParam.location, retCode );
      return TA_PERIOD_HISTORYALLOC_FAILED;
   }

   /* Because period transformation are very
    * dependend on the "delta" timestamp functions,
    * let's indepedently verify some of these.
    */
   retValue = testTimestampDelta();
   if( retValue != TA_TEST_PASS )
      return retValue;

   /* Verify everything from the checkTable. */
   for( i=0; i < CHECK_TABLE_SIZE; i++ )
   {
      /* Validate by requesting all the data in a
       * different timeframe.
       */
      memset( &histParam, 0, sizeof( TA_HistoryAllocParam ) );
      histParam.category = "TA_SIM_REF";
      histParam.symbol   = checkTable[i].symbol;
      histParam.field    = TA_ALL;
      histParam.period   = checkTable[i].period;
      histParam.flags    = checkTable[i].flags;
      retCode = TA_HistoryAlloc( unifiedDatabase, &histParam, &history );

      if( retCode != TA_SUCCESS )
      {
         printf( "%s%d.1 [%d]\n", fail_header, i, retCode );
         return TA_PERIOD_HISTORYALLOC_FAILED;
      }

      if( history->nbBars != checkTable[i].nbExpectedPriceBar )
      {
         printf( "%s%d.2 [%d != %d]\n",
                 fail_header, i,
                 history->nbBars,
                 checkTable[i].nbExpectedPriceBar );
         TA_HistoryFree( history );
         return TA_PERIOD_NBBAR_INCORRECT;
      }

      /* If the call is expected to return an empty history, no further check are done. */
      if( checkTable[i].nbExpectedPriceBar == 0 )
      {
         retCode = TA_HistoryFree( history );
         if( retCode != TA_SUCCESS )
         {
           printf( "%s%d.16 [%d]\n", fail_header, i, retCode );
           return TA_PERIOD_HISTORYFREE_FAILED;
         }
         continue;
      }

      #define CHECK_VALUE_OK(varName, subtestNo ) \
      { \
         if( !TA_REAL_EQ( history->varName[checkTable[i].thePriceBarToCheck], checkTable[i].expected_##varName, 0.01 ) ) \
         { \
            printf( "%s%d.%d [%f != %f]\n", \
                    fail_header, i, subtestNo, \
                    (TA_Real) history->varName[checkTable[i].thePriceBarToCheck], \
                    (TA_Real) checkTable[i].expected_##varName ); \
            TA_HistoryFree( history ); \
            return TA_PERIOD_PRICE_INCORRECT; \
         } \
      }

      CHECK_VALUE_OK( open,   3 );
      CHECK_VALUE_OK( high,   4 );
      CHECK_VALUE_OK( low,    5 );
      CHECK_VALUE_OK( close,  6 );
      CHECK_VALUE_OK( volume, 7 );

      if( history->openInterest != NULL )
      {
         printf( "%s%d.8\n", fail_header, i );
         TA_HistoryFree( history );
         return TA_PERIOD_OPENINTEREST_INCORRECT;
      }

      timestamp = &history->timestamp[checkTable[i].thePriceBarToCheck];
      if( TA_GetYear( timestamp ) != checkTable[i].expected_year )
      {
         printf( "%s%d.9 %d\n", fail_header, i, TA_GetYear(timestamp) );
         TA_HistoryFree( history );
         return TA_PERIOD_TIMESTAMP_YEAR_INCORRECT;
      }

      if( TA_GetMonth( timestamp ) != checkTable[i].expected_month )
      {
         printf( "%s%d.10 %d\n", fail_header, i, TA_GetMonth(timestamp) );
         TA_HistoryFree( history );
         return TA_PERIOD_TIMESTAMP_MONTH_INCORRECT;
      }

      if( TA_GetDay( timestamp ) != checkTable[i].expected_day )
      {
         printf( "%s%d.11 %d\n", fail_header, i, TA_GetDay(timestamp) );
         TA_HistoryFree( history );
         return TA_PERIOD_TIMESTAMP_DAY_INCORRECT;
      }

      if( TA_GetHour( timestamp ) != checkTable[i].expected_hour )
      {
         printf( "%s%d.12 %d\n", fail_header, i, TA_GetHour(timestamp) );
         TA_HistoryFree( history );
         return TA_PERIOD_TIMESTAMP_DAY_INCORRECT;
      }

      if( TA_GetMin( timestamp ) != checkTable[i].expected_min )
      {
         printf( "%s%d.13 %d\n", fail_header, i, TA_GetMin(timestamp) );
         TA_HistoryFree( history );
         return TA_PERIOD_TIMESTAMP_DAY_INCORRECT;
      }

      if( TA_GetSec( timestamp ) != checkTable[i].expected_sec )
      {
         printf( "%s%d.14 %d\n", fail_header, i, TA_GetSec(timestamp) );
         TA_HistoryFree( history );
         return TA_PERIOD_TIMESTAMP_DAY_INCORRECT;
      }

      retCode = TA_HistoryFree( history );
      if( retCode != TA_SUCCESS )
      {
         printf( "%s%d.15 [%d]\n", fail_header, i, retCode );
         return TA_PERIOD_HISTORYFREE_FAILED;
      }
   }

   return 0; /* Succcess. */
}
Beispiel #6
0
static TA_RetCode equityPeriodTransform( TA_PMPriv     *pmPriv,
                                         TA_Period      newPeriod, /* The new desired period. */
                                         unsigned int  *nbBars,    /* Return the number of price bar */
                                         TA_Timestamp **timestamp, /* Allocate new timestamp. */
                                         TA_Real      **equity )   /* Allocate new equity. */
{
   TA_PROLOG

   /* Notice that this function is very similar to the
    * TA_PeriodTransform function in ta_period.c
    *
    * If you find a bug here, may be worth double
    * checking TA_PeriodTransform as well...
    */
   TA_RetCode retCode;

   /* Temporaries. */
   const TA_Timestamp *tempTimestamp;
   unsigned int tempInt, tempInt2;

   /* Variable used to identify period crossing. */
   unsigned int currentWeek, currentMonth, currentYear, currentQuarter;

   /* Pointer on the history being transformed. */
   const TA_Timestamp *old_timestamp;
   const TA_Real      *old_equity;
   TA_Integer          old_nbBars;

   /* Pointer on the transformed data. */
   TA_Timestamp *new_timestamp;    /* New allocated timestamp. */
   TA_Real      *new_equity;       /* New allocated open. */
   TA_Integer    new_nbBars;

   TA_Timestamp  cur_timestamp;    /* Current new timestamp of new period. */
   TA_Real       cur_equity;       /* Current new equity of new period. */

   int oldPriceBar, newPriceBar; /* Array iterators. */
   unsigned int again, periodCompleted; /* Boolean */
   int firstIteration;

   TA_TRACE_BEGIN(  TA_PeriodTransform );

   /* Validate some mandatory parameter. */
   TA_ASSERT( newPeriod != 0 );
   TA_ASSERT( nbBars  != NULL );

   /* It is assume that the caller call this function
    * when there is really a transform to do.
    */
   TA_ASSERT( newPeriod != TA_DAILY );

   /* Of course, timestamps from the source are needed. */
   TA_ASSERT( pmPriv->arrayTimestamp != NULL );

   /* Initialize all callers pointers to NULL.
    * These will be initialize only on success.
    * In the meantime, new_XXXX pointers are
    * going to be used on the new allocated data.
    */
   if( !timestamp || !equity ) 
      return TA_BAD_PARAM;

   *timestamp = NULL;
   *equity    = NULL;
   *nbBars    = 0;

   /* Validate the supported transformation. */

   /* Eliminate all the transform that
    * are currently not supported. 
    * Identify also the major steps
    * needed to perform the transformation.
    */
   switch( newPeriod )
   {
   case TA_WEEKLY:
   case TA_MONTHLY:
   case TA_QUARTERLY:
   case TA_YEARLY:
      /* These are supported. */
      break; 
   default:
      TA_TRACE_RETURN( TA_PERIOD_NOT_AVAILABLE );
   }

   /* OK.. now proceed with the transformations. 
    * The strategy is simple:
    *   The equity for the whole period will be the 
    *   equity at the last daily price bar of 
    *   that period.
    */
   old_timestamp    = &pmPriv->arrayTimestamp[0];
   old_equity       = &pmPriv->equity[0];
   old_nbBars       = pmPriv->nbDailyBars;

   new_timestamp    = NULL;
   newPriceBar      = 0;

   cur_timestamp.date = 0;    /* Current new timestamp of new period. */
   cur_timestamp.time = 0;    /* Current new timestamp of new period. */
   

   /* Overestimate the number of required new price bar. */
   switch( newPeriod )
   {
   case TA_WEEKLY:
      retCode = TA_TimestampDeltaWeek( &old_timestamp[0], &old_timestamp[old_nbBars-1], (unsigned int *)&new_nbBars );
         break;
   case TA_MONTHLY:
      retCode = TA_TimestampDeltaMonth( &old_timestamp[0], &old_timestamp[old_nbBars-1], (unsigned int *)&new_nbBars );
      break;
   case TA_QUARTERLY:
      retCode = TA_TimestampDeltaQuarter( &old_timestamp[0], &old_timestamp[old_nbBars-1], (unsigned int *)&new_nbBars );
      break;
   case TA_YEARLY:
      retCode = TA_TimestampDeltaYear( &old_timestamp[0], &old_timestamp[old_nbBars-1], (unsigned int *)&new_nbBars );
      break;
   default:
      TA_TRACE_RETURN( TA_INTERNAL_ERROR(126) );
   }

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

   new_nbBars += 2; /* To be on the safe side */

   /* Allocate the new data. */      
   new_timestamp = TA_Malloc( new_nbBars * sizeof( TA_Timestamp ) );
   if( !new_timestamp )
   {
      TA_TRACE_RETURN( TA_ALLOC_ERR );
   }
   new_equity = TA_Malloc( new_nbBars * sizeof( TA_Real ) );
   if( !new_equity )
   {
      TA_Free(  new_timestamp );
      TA_TRACE_RETURN( TA_ALLOC_ERR );
   }
      
   /* Allows to detect crossing of the new period. */
   currentYear    = TA_GetYear ( &old_timestamp[0] );
   currentMonth   = TA_GetMonth( &old_timestamp[0] );
   currentWeek    = TA_GetWeekOfTheYear( &old_timestamp[0] );
   currentQuarter = TA_GetQuarterOfTheYear( &old_timestamp[0] );

   /* Iterate through the old price bar. */
   oldPriceBar = 0;

   /* Iterate through the new price bar. */
   newPriceBar = 0;

   again = 1; /* Becomes false when all bars are processed. */
   while( again )
   {
      /* Initialize cur_XXXXXX variables with the first bar in old timeframe. */
      cur_timestamp = old_timestamp[oldPriceBar];
      cur_equity    = old_equity   [oldPriceBar];

      /* Go through the bars and accumulate the info
       * until the end of the requested period is reach.
       */
      periodCompleted = 0;
      firstIteration = 1;
      while( (oldPriceBar < old_nbBars) && !periodCompleted )
      {
         tempTimestamp = &old_timestamp[oldPriceBar];

         /* Check if we reached an end of period. */
         switch( newPeriod )
         {
         case TA_WEEKLY:
            tempInt  = TA_GetWeekOfTheYear( tempTimestamp );

            /* Trap weeks on years boundary. */
            if( (currentWeek == 52) && (tempInt == 0) )
               currentWeek = 0;
            else if( currentWeek != tempInt )
            {
               periodCompleted = 1;
               currentWeek = tempInt;
            }
            break;
         case TA_MONTHLY:
            tempInt  = TA_GetMonth( tempTimestamp );
            tempInt2 = TA_GetYear(tempTimestamp);
            if( (currentMonth != tempInt) ||
                (currentYear  != tempInt2) )
            {
               periodCompleted = 1;
               currentMonth    = tempInt;
               currentYear     = tempInt2;
            }
            break;
         case TA_QUARTERLY:
            tempInt = TA_GetQuarterOfTheYear( tempTimestamp );
            tempInt2 = TA_GetYear(tempTimestamp);

            if( (currentQuarter != tempInt) ||
                (currentYear    != tempInt2) )
            {
                  periodCompleted = 1;
                  currentQuarter  = tempInt;
                  currentYear     = tempInt2;
            }
            break;
         case TA_YEARLY:
            tempInt = TA_GetYear( tempTimestamp );
            if( currentYear != tempInt )
            {
               periodCompleted = 1;
               currentYear = tempInt;
            }
            break;
         default:
            /* Do nothing */
            break;
         }

         /* If this is not the end of a period (in the new timeframe)
          * just accumulate the data. If this is the end of the period
          * that while loop will be exited.
          * Nothing is done on the first iteration because all the 
          * cur_XXXX variables have been already initialized.
          */
         if( !periodCompleted )
         {
            if( !firstIteration )
            {
               /* Adjust the new price bar. */
               cur_timestamp = old_timestamp[oldPriceBar];
               cur_equity    = old_equity   [oldPriceBar];
            }
            else
               firstIteration = 0;

            /* Move to next bar. */
            oldPriceBar++;
         }
      }
      /* We got all the info needed in the cur_XXXXX variables for
       * proceeding with the initialization of the new period price bar.
       */
      TA_DEBUG_ASSERT( newPriceBar < new_nbBars );

      /* If the timestamp is requested, some adjustment could be
       * needed to cur_timestamp.
       */
      switch( newPeriod )
      {
      case TA_WEEKLY:
            /* Now something a little bit tricky, we must
             * make sure that this new price bar is reported
             * as being the Friday of that week (even if there 
             * is no price bar for that Friday).
             */
            TA_JumpToDayOfWeek( &cur_timestamp, TA_FRIDAY );
            break;
      case TA_MONTHLY:
            /* Monthly timestamp always end with the last day of
             * the month. Even if there was no actual transaction
             * the last day.
             */
            TA_JumpToEndOfMonth( &cur_timestamp );
            break;
      case TA_QUARTERLY:
            /* Quarterly timestamp always end with the last day of
             * the quarter. Even if there was no actual transaction
             * the last day.
             * Quarter 1 =  3/31
             * Quarter 2 =  6/30
             * Quarter 3 =  9/30
             * Quarter 4 = 12/31
             */
            TA_JumpToEndOfQuarter( &cur_timestamp );
            break;
      case TA_YEARLY:
            /* Yearly data always end on 12/31. */
            TA_JumpToEndOfYear( &cur_timestamp );
            break;
      default:
            /* Do nothing. */
            break;
      }

      /* The new price bar is initialized here. */
      new_timestamp[newPriceBar] = cur_timestamp;
      new_equity   [newPriceBar] = cur_equity;
                     
      /* This new period bar is completed, move to the next one. */
      newPriceBar++;

      /* Any more data to process? */
      if( oldPriceBar >= old_nbBars)
         again = 0; /* All bars have been processsed. */
   }

   /* All done! Return the final result to the caller. */
   *equity    = new_equity;
   *timestamp = new_timestamp;
   *nbBars    = newPriceBar;

   TA_TRACE_RETURN( TA_SUCCESS );
}
Beispiel #7
0
static ErrorNumber checkRangeSame( TA_UDBase          *udb,
                                   const TA_History   *historyRef,
                                   const TA_Timestamp *start,
                                   const TA_Timestamp *end,      
                                   TA_Period           period,                             
                                   unsigned int        startIdx,
                                   unsigned int        nbPriceBar )
{
   TA_History *history;
   unsigned int i;
   TA_RetCode retCode;
   TA_HistoryAllocParam histParam;

   int retry, again;
   /* Try up to 10 times to get the requested number of 
    * price bar (sometimes Yahoo! or the Web do fail to
    * return the data).
    */
   again = 1;
   for( retry=0; (retry < 10) && again; retry++ )
   {
      memset( &histParam, 0, sizeof( TA_HistoryAllocParam ) );
      histParam.category = "CA.TSE.STOCK";
      histParam.symbol   = "NT";
      histParam.field    = TA_ALL;
      histParam.start    = *start;
      histParam.end      = *end;
      histParam.period   = period;
      retCode = TA_HistoryAlloc( udb, &histParam, &history );

      if( (retCode == TA_SUCCESS) && (history->nbBars == nbPriceBar) )
         again = 0;
      else
      {
         printf( "Warning: Yahoo! history alloc retry #%d of 10\n", retry+1 );
         if( retCode == TA_SUCCESS )
         {
            TA_HistoryFree( history );
         }
         TA_Sleep( 10 /* seconds */ );
      }
   }

   if( retCode != TA_SUCCESS )
   {
      reportError( "TA_HistoryAlloc", retCode );
      return TA_YAHOO_CRS_HISTORYALLOC_FAILED;
   }

   /* Check that the expected number of price bar is returned. */
   if( history->nbBars != nbPriceBar )
   {
      printf( "Failed: nbBars (received != requested)=(%d != %d)\n",
              history->nbBars, nbPriceBar );

      TA_HistoryFree( history );
      return TA_YAHOO_CRS_NBBARSBAD;
   }

   /* printf( "startIdx=%d\n", startIdx ); */

   /* Check that the data is the same for the range. */
   for( i=0; i < nbPriceBar; i++ )
   {
      if( !TA_TimestampEqual( &history->timestamp[i], &historyRef->timestamp[startIdx+i] ) ||
          (history->open[i] != historyRef->open[startIdx+i]) ||
          (history->high[i] != historyRef->high[startIdx+i]) ||
          (history->low[i] != historyRef->low[startIdx+i]) ||
          (history->close[i] != historyRef->close[startIdx+i]) ||
          (history->volume[i] != historyRef->volume[startIdx+i]) )
      {
         printf( "Failed: Price Bar value different\n" );
         printf( "Failed: Data = %d/%d/%d : %f,%f,%f,%f,%d\n",
                                             TA_GetMonth(&history->timestamp[i]),
                                             TA_GetDay(&history->timestamp[i]),
                                             TA_GetYear(&history->timestamp[i]),
                                             history->open[i],
                                             history->high[i],         
                                             history->low[i],
                                             history->close[i],
                                             history->volume[i] );
         printf( "Failed: Ref  = %d/%d/%d : %f,%f,%f,%f,%d\n",
                                             TA_GetMonth(&historyRef->timestamp[i]),
                                             TA_GetDay(&historyRef->timestamp[i]),
                                             TA_GetYear(&historyRef->timestamp[i]),
                                             historyRef->open[startIdx+i],
                                             historyRef->high[startIdx+i],     
                                             historyRef->low[startIdx+i],
                                             historyRef->close[startIdx+i],
                                             historyRef->volume[startIdx+i] );

         TA_HistoryFree( history );
         return TA_YAHOO_CRS_PRICEBARBAD;
      }
   }

   retCode = TA_HistoryFree( history );
   if( retCode != TA_SUCCESS )
   {
      reportError( "TA_HistoryFree", retCode );
      return TA_YAHOO_HISTORYFREE_FAILED;
   }

   return TA_TEST_PASS;
}
Beispiel #8
0
TA_RetCode TA_EstimateAllocInit( const TA_Timestamp *start,
                                 const TA_Timestamp *end,
                                 TA_Period period,
                                 unsigned int minimumSize,
                                 unsigned int maximumSize,
                                 TA_EstimateInfo *estimationInfo,
                                 unsigned int *nbElementToAllocate )
{
   unsigned int nbElement;

   #if 0
      /* Force extrems value for testing. */
      *nbElementToAllocate = 1;
      return TA_SUCCESS;
   #endif

   nbElement = minimumSize; /* Default */

   if( start && end )
   {
      switch( period )
      {
      case TA_DAILY:
         TA_TimestampDeltaDay( start, end, &nbElement );
         break;
      case TA_WEEKLY:
         TA_TimestampDeltaWeek( start, end, &nbElement );
         break;
      case TA_MONTHLY:
         TA_TimestampDeltaMonth( start, end, &nbElement );
         break;
      case TA_QUARTERLY:
         TA_TimestampDeltaQuarter( start, end, &nbElement );
         break;
      case TA_YEARLY:
         TA_TimestampDeltaYear( start, end, &nbElement );
         break;
      default:
         if( (period >= TA_1SEC) && (period <= TA_1HOUR) )
         {
            /* Estimate the number of day */
            if( (TA_GetDay  (start) != TA_GetDay  (end)) ||
                (TA_GetMonth(start) != TA_GetMonth(end)) ||
                (TA_GetYear (start) != TA_GetYear (end)) )
            {
               /* Estimate assuming market is open for 8 hours per day 
                * (it does not hurt to slightly under or over estimate)
                */
               TA_TimestampDeltaDay( start, end, &nbElement );
               nbElement *= (8*60*60);
               nbElement /= period;
            }
            else
            {
               nbElement = (8*60*60);
               nbElement /= period;
            }
         }
         break;
      }
      nbElement += 2;
   }

   /* Make the estimation fits within the max/min provided. */
   estimationInfo->maximumSize = maximumSize;
   estimationInfo->minimumSize = minimumSize;
   if( nbElement > maximumSize )
      nbElement = maximumSize;

   if( nbElement < minimumSize )
      nbElement = minimumSize;

   *nbElementToAllocate = nbElement;

   return TA_SUCCESS;
}