// Zorro lite-C, by ChatGPT-6. Save in Strategy, select it, click [Test].
// Each OHLC field is compared with the same field of the previous,
// already corrected candle. The oldest candle is the unchanged seed.
// Factor > 1: allowed interval is [Previous/Factor, Previous*Factor].
// Assumes positive prices. Timestamps, fVal, and fVol are preserved.
// The original is backed up with appended "bk".
// +1 = upward outlier, -1 = downward outlier, 0 = within bounds.
int outlierSide(var Price, var Previous, var Factor)
{
if(Price > Previous*Factor) return 1;
if(Price < Previous/Factor) return -1;
return 0;
}
// Returns the number of repaired fields, or -1 on failure.
int removeT6Outliers(string FileName, var Factor)
{
if(!(Factor > 1)) {
printf("\nFactor must be greater than 1.");
return -1;
}
if(strlen(FileName)+3 > 1024) {
printf("\nFile path too long.");
return -1;
}
char Backup[1024];
strx(Backup,1024,FileName,".t6","bk.t6");
// T6 has seven dataset fields: timestamp plus six floats.
int N = dataLoad(1,FileName,7);
if(N < 2) {
printf("\nCannot read T6 candles from %s",FileName);
return -1;
}
T6* Candles = (T6*)dataStr(1,0,0);
size_t Bytes = (size_t)N*sizeof(T6);
if(file_length(FileName) != Bytes) {
printf("\nInvalid T6 file size.");
return -1;
}
// Reject an incorrectly ordered file before modifying anything on disk.
int i;
for(i = 0; i < N-1; i++) {
if(Candles[i].time < Candles[i+1].time) {
printf("\nT6 timestamps must be in descending order.");
return -1;
}
}
int Fixed = 0;
// Newest is index 0; the previous candle is at i+1.
for(i = N-2; i >= 0; i--) {
T6* Current = Candles+i;
T6* Previous = Candles+i+1;
if(!(Previous->fOpen > 0 && Previous->fClose > 0
&& Previous->fHigh > 0 && Previous->fLow > 0)) {
printf("\nNonpositive reference price at record %i; file unchanged.",i+1);
return -1;
}
var Distance = abs((var)Previous->fOpen-Previous->fClose);
int Side = outlierSide(Current->fOpen,Previous->fOpen,Factor);
if(Side) {
Current->fOpen = Previous->fOpen+Side*Distance;
Fixed++;
}
Side = outlierSide(Current->fClose,Previous->fClose,Factor);
if(Side) {
Current->fClose = Previous->fClose+Side*Distance;
Fixed++;
}
// Clip outlying wicks to the repaired candle body. Also ensure
// that high and low enclose open and close after their repair.
var Top = max(Current->fOpen,Current->fClose);
var Bottom = min(Current->fOpen,Current->fClose);
if(outlierSide(Current->fHigh,Previous->fHigh,Factor)
|| Current->fHigh < Top) {
Current->fHigh = Top;
Fixed++;
}
if(outlierSide(Current->fLow,Previous->fLow,Factor)
|| Current->fLow > Bottom) {
Current->fLow = Bottom;
Fixed++;
}
}
// Make the backup from the untouched input, not the corrected array.
if(!file_copy(Backup,FileName) || file_length(Backup) != Bytes) {
printf("\nBackup failed; input not overwritten.");
return -1;
}
if(!file_write(FileName,(string)Candles,Bytes)
|| file_length(FileName) != Bytes) {
printf("\nOutput write failed. Original preserved in %s.",Backup);
return -1;
}
printf("\n%i fields repaired in %i candles.\nOutput: %s\nOriginal: %s",
Fixed,N,FileName,Backup);
return Fixed;
}
void main()
{
var Factor = 1.03; // Adjust the maximum permitted price ratio here.
string FileName = file_select("History","T6 files\0*.t6\0\0");
if(FileName && FileName[0])
removeT6Outliers(FileName,Factor);
}