amibroker

Home ▸ Knowledge 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 = Cross( MACD(), Signal() );

filepath = "C:\\ScanExport.txt";

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

// open file in "share-aware" append mode
fh = fopen( filepath, "a", True );

// proceed if file handle is correct
if ( fh )
{
   
lastbuyDT =  LastValue( ValueWhen( Buy, DateTime() ) ) ;

   
// write to file
   
fputs( Name() +", Last Buy: " + DateTimeToStr( lastBuyDT ) +"\n", fh );

   
// close file handle
   
fclose( fh );
}
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 

#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 = Matrix( rows, cols, initvalue)

then in order to access matrix elements, we need to use:
x = my_var_name[ row ][ 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[ 0 ][ 0 ] = 1; A[ 0 ][ 1 ] = 4; A[ 0 ][ 2 ] = 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 = Matrix( rows, cols, 0 );

// open file
fh = fopen( file, "r" );

if( 
fh )
{
    
i = 0;

    
// iterate through the lines of input file
    
for( i = 0; ! feof( fh ) AND i < rows; i++ ) 
    {
        
// read a line of text
        
line = fgets( fh ); 

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

// spot check selected element
Title = "spot check M[ 2 ][ 3 ]: " + NumToStr( MyMatrix[ 2 ][ 3 ] )