TA_RetCode TA_PMAlloc( const TA_Timestamp *startDate, const TA_Timestamp *endDate, TA_Real initialCapital, TA_PM **allocatedPM ) { TA_PM *pm; TA_PMPriv *pmPriv; unsigned int delta; TA_RetCode retCode; /* Check all the parameters. */ if( !allocatedPM ) return TA_BAD_PARAM; *allocatedPM = NULL; if( !startDate || !endDate ) return TA_BAD_PARAM; if( TA_TimestampValidate( startDate ) ) return TA_BAD_START_DATE; if( TA_TimestampValidate( endDate ) || TA_TimestampGreater( startDate, endDate ) ) return TA_BAD_END_DATE; /* To keep things simple, it is assumed that * the requested date range contains at least * one weekday. */ retCode = TA_TimestampDeltaWeekday( startDate, endDate, &delta ); if( retCode != TA_SUCCESS ) return retCode; if( delta <= 0 ) return TA_NO_WEEKDAY_IN_DATE_RANGE; /* Allocate the public and private structure. */ pm = TA_Malloc( sizeof( TA_PM ) + sizeof( TA_PMPriv ) ); if( !pm ) return TA_ALLOC_ERR; memset( pm, 0, sizeof( TA_PM ) + sizeof( TA_PMPriv ) ); pmPriv = (TA_PMPriv *)(((char *)pm)+sizeof(TA_PM)); pmPriv->magicNb = TA_PMPRIV_MAGIC_NB; pmPriv->initialCapital = initialCapital; pm->hiddenData = pmPriv; TA_ListInit( &pmPriv->tradeLogList ); /* TA_PMFree can be safely called from this point. */ TA_TimestampCopy( &pmPriv->endDate, endDate ); TA_TimestampCopy( &pmPriv->startDate, startDate ); /* Success, return the allocated data to the caller. */ *allocatedPM = pm; return TA_SUCCESS; }
static int isGapAcceptable( TA_Timestamp *lastBarTimestampAdded, TA_Timestamp *lastBarTimestamp ) { TA_RetCode retCode; unsigned int deltaDay, i; /* Verify if that gap in the data is acceptable. This is not * a "perfect" algorithm, but the idea is to avoid obvious * failure. Small failure might get through, but the consequence * won't be worst than a long week-end gap. */ retCode = TA_TimestampDeltaDay( lastBarTimestampAdded, lastBarTimestamp, &deltaDay ); if( (retCode != TA_SUCCESS) || (deltaDay >= 7) ) { /* A gap of more than 7 days is an error for sure. Or may be the symbol * is not being traded anymore? Don't take a chance and return an error. */ return 0; } /* The gap should not be more than 3 weekdays (after removing special case) */ retCode = TA_TimestampDeltaWeekday( lastBarTimestampAdded, lastBarTimestamp, &deltaDay ); if( retCode != TA_SUCCESS ) { return 0; } /* Handle special cases */ /* Trading were suspended on many exchange on september 11 2001 to september 14 2001 */ for( i=11; i <= 14; i++ ) { if( TA_DateWithinRange( 2001,9,i, lastBarTimestampAdded, lastBarTimestamp ) ) --deltaDay; } /* Handling holidays would be better here, any volunteer to implement this? */ if( deltaDay > 3 ) return 0; return 1; /* The gap is acceptable. */ }
/* Period transformation is highly dependable on * the function evaluating the 'delta' between * two timestamp, so this is verified here. */ static ErrorNumber testTimestampDelta( void ) { TA_RetCode retCode; unsigned int i, delta; /* !!! A lot more of testing could be added !!! */ /* Test weekday delta. */ TA_SetDate( 2002, 12, 29, &sundayTS ); TA_SetDate( 2002, 12, 30, &mondayTS ); TA_SetDate( 2002, 12, 31, &tuesdayTS ); TA_SetDate( 2003, 1, 1, &wednesdayTS ); TA_SetDate( 2003, 1, 2, &thursdayTS ); TA_SetDate( 2003, 1, 3, &fridayTS ); TA_SetDate( 2003, 1, 4, &saturdayTS ); TA_SetDate( 2003, 1, 5, &sunday2TS ); TA_SetDate( 2003, 1, 6, &monday2TS ); TA_SetDate( 2003, 1, 7, &tuesday2TS ); TA_SetDate( 2003, 1, 8, &wednesday2TS ); TA_SetDate( 2003, 1, 9, &thursday2TS ); TA_SetDate( 2003, 1, 10, &friday2TS ); TA_SetDate( 2003, 1, 11, &saturday2TS ); for( i=0; i < NB_WEEKDAY_CHECK_TO_DO; i++ ) { retCode = TA_TimestampDeltaWeekday( toCheck[i].start, toCheck[i].end, &delta ); if( retCode != TA_SUCCESS ) { printf( "Failed: Weekday delta test #%d\n", i ); return TA_PERIOD_DELTA_WEEKDAY_FAILED; } if( delta != toCheck[i].expectedDelta ) { printf( "Failed: Expected delta != delta (%d!=%d) for test #%d\n", toCheck[i].expectedDelta, delta, i ); return TA_PERIOD_DELTA_WEEKDAY_FAILED_1; } } return TA_TEST_PASS; /* Success. */ }
static int findTimestampIndex( const TA_PMPriv *pmPriv, const TA_Timestamp *exitTimestamp, int *idx ) { const TA_Timestamp *startDate; const TA_Timestamp *endDate; TA_DayOfWeek dayOfTheWeek; /* Return 0 when no index can be resolved. */ startDate = &pmPriv->startDate; endDate = &pmPriv->endDate; /* Make sure the exitTimestamp is within the start/end date. */ if( (TA_TimestampGreater(exitTimestamp,startDate)&&TA_TimestampLess(exitTimestamp,endDate)) || TA_TimestampEqual(exitTimestamp, startDate) || TA_TimestampEqual(exitTimestamp, endDate) ) { /* Make sure the exitTimestamp is NOT on week-end. Week-end * trades are currently ignored. */ dayOfTheWeek = TA_GetDayOfTheWeek( exitTimestamp ); if( (dayOfTheWeek != TA_SUNDAY) && (dayOfTheWeek != TA_SATURDAY) ) { TA_TimestampDeltaWeekday( startDate, exitTimestamp, (unsigned int *)idx ); *idx -= 1; #ifdef TA_DEBUG TA_ASSERT_RET( *idx >= 0, 0 ); TA_ASSERT_RET( (unsigned int)*idx < pmPriv->nbDailyBars, 0 ); TA_ASSERT_RET( TA_TimestampEqual(&pmPriv->arrayTimestamp[*idx], exitTimestamp ), 0 ); #endif return 1; } } /* No index can be found, initialize to zero, just to * be safe. */ *idx = 0; return 0; }
static TA_Timestamp *allocTimestampArray( const TA_Timestamp *start, const TA_Timestamp *end, int *nbDays ) { TA_RetCode retCode; TA_Timestamp *array; int outIdx; TA_Timestamp curDate; TA_DayOfWeek dayOfTheWeek; TA_ASSERT_RET( TA_TimestampValidate(start) == TA_SUCCESS, (TA_Timestamp *)NULL ); TA_ASSERT_RET( TA_TimestampValidate(end ) == TA_SUCCESS, (TA_Timestamp *)NULL ); TA_ASSERT_RET( nbDays != NULL, (TA_Timestamp *)NULL ); /* Calculate the exact number of week days * between start and end inclusive. * Excluding week-ends. */ retCode = TA_TimestampDeltaWeekday( start, end, (unsigned int *)nbDays ); if( retCode != TA_SUCCESS ) return (TA_Timestamp *)NULL; /* Allocate the array. Add two element just to be on the safe side. */ array = TA_Malloc( sizeof( TA_Timestamp ) * ((*nbDays)+2) ); if( !array ) return (TA_Timestamp *)NULL; /* Fill up the array. */ TA_TimestampCopy( &curDate, start ); /* Write the start point, if it is a weekday. */ outIdx = 0; dayOfTheWeek = TA_GetDayOfTheWeek( &curDate ); if( (dayOfTheWeek != TA_SUNDAY) && (dayOfTheWeek != TA_SATURDAY) ) { TA_TimestampCopy( &array[outIdx], &curDate ); outIdx++; TA_NextWeekday( &curDate ); TA_ASSERT_RET( TA_TimestampValidate(&curDate) == TA_SUCCESS, (TA_Timestamp *)NULL ); } /* Count the number of weekday */ while( TA_TimestampLess( &curDate, end ) ) { TA_TimestampCopy( &array[outIdx], &curDate ); outIdx++; TA_NextWeekday( &curDate ); TA_ASSERT_RET( TA_TimestampValidate(&curDate) == TA_SUCCESS, (TA_Timestamp *)NULL ); } /* Check if the ending point is a weekday. */ if( TA_TimestampEqual( &curDate, end ) ) { dayOfTheWeek = TA_GetDayOfTheWeek( &curDate ); if( (dayOfTheWeek != TA_SUNDAY) && (dayOfTheWeek != TA_SATURDAY) ) TA_TimestampCopy( &array[outIdx++], &curDate ); } TA_ASSERT_RET( outIdx == (*nbDays), (TA_Timestamp *)NULL ); return array; }