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