amibroker

HomeKnowledge Base

How to write to single shared file in multi-threaded scenario

The problem is as follows: during multiple-symbol Scan (or any other multi-threaded Analysis operation) we want to create a single, shared file and append content generated from multiple symbols to it.

There are two things that we must consider if we are running in multiple treaded scenario.
1. If we want to get just single-run results, before appending content to the file, we need first to delete file generated in previous runs.

2. We have to take care to open the file in share-aware mode so multiple threads do not write at the same time (preventing corruption).

A sample formula is presented below.

// our scanning code
Buy CrossMACD(), Signal() );

filepath "C:\\ScanExport.txt";

if( 
Status("stocknum") == )
{
   
// delete previous file before anything else
   
fdeletefilepath );
}

// open file in "share-aware" append mode  
fh fopenfilepath"a"True );

// proceed if file handle is correct
if ( fh )
{
   
lastbuyDT =  LastValueValueWhenBuyDateTime() ) ) ;

   
// write to file
   
fputsName() +", Last Buy: " DateTimeToStrlastBuyDT ) +"\n"fh );

   
// close file handle
   
fclosefh );
}
else
{
  
_TRACE("Failed to open the file");
}

One important thing to remember is that in multi-threaded environment threads execute independently and there is no guarantee they will all execute sequentially, so the order of items (symbols) in the file may not be alphabetical.

If we want strictly sequential execution, then we must limit ourselves to just running in single-thread. A single-thread execution in New Analysis window can be achieved by placing the following pragma call at the top of the formula.

#pragma maxthreads 1

#pragma maxthreads limits the number of parallel threads used by New Analysis window. This command is available in AmiBroker version 6 or higher.

How to populate Matrix from a text file

AmiBroker 6.00 has introduced support for matrices. After we create a matrics with Matrix function call:

my_var_name Matrixrowscolsinitvalue);

then in order to access matrix elements, we need to use:

my_var_namerow ][ col ];

However – if we want to populate a relatively large matrix with values generated in other programs, then it may not be very practical to do it by hand in the AFL code assigning individual elements like this:

A][ ] = 1A][ ] = 4A][ ] = 6;

What we can do in such case is to store the values in a text file that we could use as input, then read through the file using fgets function and populate Matrix elements using a looping code. A sample formula showing how to perform such task is presented below.

A sample text file for this example can be found here: http://www.amibroker.com/kb/wp-content/uploads/2015/10/samplematrix.txt

// the input file path
file "C:\\samplematrix.txt";

// define the size of the desired matrix
rows 16;
cols 16;

// create matrix
myMatrix Matrixrowscols);

// open file
fh fopenfile"r" );

if( 
fh )
{
    
0;

    
// iterate through the lines of input file
    
for( 0; ! feoffh ) AND rowsi++ ) 
    {
        
// read a line of text
        
line fgetsfh ); 

        if( 
line == "" )
        {
            
Error("Too few rows in the data file or an empty row found");
            break;
        }
    
        
// iterate through the elements of the line
        
for( 0; ( item StrExtractline) ) != "" AND colsj++ ) 
        {
            
// assign matrix element
            
myMatrix][ ] = StrToNumitem );
        }
        
        if( 
cols )
        {
            
Error("Too few columns in data file");
            break;
        }
    }
    
    
fclosefh );
}
else
{
    
Error"ERROR: file can not be opened" );
}

// spot check selected element
Title "spot check M[ 2 ][ 3 ]: " NumToStrMyMatrix][ ] );