[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [system-traders] MetaStockReader?



Le Wed, Nov 12, 2003 at 12:11:59AM +0100, Pirani Enrico écrivait:
> Hi,

Hi,

> I would like to ask you if the metatstock.pm module works only in windows,
> or there is a way to comunicate with a Metastock db even under Linux ?.

Yes there is. The metastock.pm uses the program attached. It was
authored by Fabien Fulhaber.

Cheers,
-- 
Raphaël Hertzog -+- http://www.ouaza.com
Formation Linux et logiciel libre : http://www.logidee.com
Earn money with free software: http://www.geniustrader.org
/******************************************************************************/
/*                                                                            */
/*   MetaStock & Computrac Reader                                             */
/*                                                                            */
/*   Copyright (c) 2001 Fabien Fulhaber. All Rights Reserved.                 */
/*                                                                            */
/*   MetaStock is a registered trademark of EQUIS International Inc.          */
/*   Computrac is a registered trademark of Dow Jones Telerate.               */
/*                                                                            */
/*   Last-Modified : Mar Sep 04 18:25:22 CET 2001                             */
/*                                                                            */
/******************************************************************************/

/******************************************************************************/
/*   MetaStockReader : INCLUDES                                               */
/******************************************************************************/

#include <stdio.h>
#include <string.h>
#include <sys/dir.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <stdlib.h>

/******************************************************************************/
/*   MetaStockReader : TYPEDEFS                                               */
/******************************************************************************/

typedef	unsigned char	u_char;
typedef	unsigned short	u_short;
typedef	unsigned long	u_long;

/******************************************************************************/
/*   MetaStockReader : STRUCTS                                                */
/******************************************************************************/

struct Master_file_header {
    u_short num_files;		// Number of files master contains
    u_short file_num;		// Highest F# to use
    char zeroes[49];		// Nothing or copyright info
};

struct Master_file_record {
    u_char file_num;		// File number : F#
    char file_type[2];		// CT file type = 0'e' (5 or 7 flds)
    u_char rec_len;		// Record length in bytes (4 x num_fields)
    u_char num_fields;		// Number of 4-byte fields in each record in the data file
    char reserved1[2];
    char issue_name[16];	// Issue name
    char reserved2;
    char CT_v2_8_flag;		// If CT ver. 2.8, 'Y'; o.w., anything else
    float first_date;		// First date in yymmdd format
    float last_date;		// Last date in yymmdd format
    char time_frame;		// Time frame : I = Intraday D = Daily / W = Weekly / M = Monthly / Q = Quarterly / Y = Yearly
    u_short ida_time;		// Time interval, the time between trades in minute intervals, minimum 1 minute
    char symbol[14];		// Symbol
    char reserved3;		// Reserved (must be a space)
    char flag;			// ' ' or '*' for autorun
    char reserved4;
};

struct Master_file {
   Master_file_header header;
   Master_file_record record;
};

struct Data_file_header {
    u_short max_recs;
    u_short last_rec;
    char zeroes[28];
};

struct Data_file_record {
    float date;
    float time;
    float open;
    float high;
    float low;
    float close;
    float volume;
    float op_int;
};

/******************************************************************************/
/*   MetaStockReader : DECLARATIONS                                           */
/******************************************************************************/

class MetaStockDataBase
{
    public:
    MetaStockDataBase();
    ~MetaStockDataBase();

    bool initialize(char *directory, bool recursive = false);
    void get_quotes(char *symbol);

    private:

    Master_file_header get_master_file_header(FILE *fp);
    Master_file_record get_master_file_record(FILE *fp, int go_to_record_number);

    char ** get_all_master_files(char *directory, bool recursive = false);

};

/******************************************************************************/
/*   MetaStockReader : GLOBAL VARIABLES                                       */
/******************************************************************************/

bool init_recursive = false;
char *init_directory = NULL;
char **resultats = NULL;
int taille_resultats = 0;
int master_file_id = 0;

/******************************************************************************/
/*   fmsbin2ieee : Microsoft Basic floating point format to IEEE floating     */
/*                 point format                                               */
/******************************************************************************/

int fmsbin2ieee(float *src, float *dst) {

    union {
	float a;
	u_long b;
    } c;
    u_short man;
    u_short exp;

    c.a = *src;

    if (c.b) {		// not zero
	man = c.b >> 16;
	exp = (man & 0xff00) - 0x0200;
	if ((exp & 0x8000) != (man & 0x8000))
	    return 1;	// exponent overflow
	man = (man & 0x7f) | ((man << 8) & 0x8000);	// move sign
	man |= exp >> 1;
	c.b = (c.b & 0xffff) | ((long)man << 16);
    }

    *dst = c.a;

    return 0;
}

/******************************************************************************/
/*   fieee2msbin : IEEE floating point format to Microsoft Basic floating     */
/*                 point format                                               */
/******************************************************************************/

int fieee2msbin(float *src, float *dst) {
    union {
	float a;
	u_long b;
    } c;
    u_short man;
    u_short exp;

    c.a = *src;
    if (c.b) {		/* not zero */
	man = c.b >> 16;
	exp = ((man << 1) & 0xff00) + 0x0200;
	if ((exp & 0x8000) != ((man << 1) & 0x8000))
	    return 1;	/* exponent overflow */
	man = (man & 0x7f) | ((man >> 8) & 0x80);	/* move sign */
	man |= exp;
	c.b = (c.b & 0xffff) | ((long)man << 16);
    }
    *dst = c.a;
    return 0;
}

/******************************************************************************/
/*   read_dat_file : Read and print all records for a specific DAT file       */
/******************************************************************************/

bool read_dat_file(FILE *df, Master_file_record master_file_record) {
   
   if (df != (FILE *)NULL) {
      
      Data_file_header data_file_header;
      Data_file_record data_file_record;

      float last_record;
      float first_date;

      float last_date;
      float record_date;
      float record_time;
      float record_open;
      float record_high;
      float record_low;
      float record_close;
      float record_volume;
      float record_op_int;

      /* The following code is currently not necessary but might be usefull one day...
      
      if ( fmsbin2ieee((float *) &master_file_record.first_date, &first_date) == 0) {
         printf("First date : %f\n", first_date);
      }

      if ( fmsbin2ieee((float *) &master_file_record.last_date, &last_date) == 0) {
         printf("Last date : %f\n", last_date);
      }

      printf("Time frame : %c\n", master_file_record.time_frame);
 
      if (master_file_record.time_frame == 'I') {
         printf("Time interval : %u minute(s)\n", master_file_record.ida_time);
      }

      printf("\n");
      
      */

      fread(&data_file_header.max_recs, sizeof(data_file_header.max_recs), 1, df);
      fread(&data_file_header.last_rec, sizeof(data_file_header.last_rec), 1, df);

      if (master_file_record.num_fields == 5) {
         fread(&data_file_header.zeroes, sizeof(char), 16, df);
      }
      if (master_file_record.num_fields == 6) {
         fread(&data_file_header.zeroes, sizeof(char), 20, df);
      }
      if (master_file_record.num_fields == 7) {
         fread(&data_file_header.zeroes, sizeof(char), 24, df);
      }
      if (master_file_record.num_fields == 8) {
         fread(&data_file_header.zeroes, sizeof(char), 28, df);
      }

      /* The following code is currently not necessary but might be usefull one day...
      
      printf("Total Record Number : %u\n", data_file_header.max_recs);
      printf("Highest Record Used : %u\n", data_file_header.last_rec);
      printf("Zeroes : %s\n", data_file_header.zeroes);
      printf("\n");

      */

      last_record = data_file_header.last_rec;

      // Build and print record's header according to the fields we have
      printf("Date\t");
      if (master_file_record.time_frame == 'I') {
	  printf("Time\t");
      }
      if (((master_file_record.time_frame == 'D') && ((master_file_record.num_fields == 6) || (master_file_record.num_fields == 7) || (master_file_record.num_fields == 8))) || ((master_file_record.time_frame == 'I') && ((master_file_record.num_fields == 7) || (master_file_record.num_fields == 8)))) {
	  printf("Open\t");
      }
      printf("High\tLow\tClose\tVolume\n");

      // Get and print all record available, in the same order than the header
      for (int i=0; i < last_record - 1; i++) {
         
	 // Record's Date
	 fread(&data_file_record.date, sizeof(data_file_record.date), 1, df);
         if ( fmsbin2ieee((float *) &data_file_record.date, &record_date) == 0) {
	     int date = int(record_date);
	     char date_str[6], new_date[8];
	     sprintf(date_str, "%i", date);

	     // Swap fields order from yymmdd to ddmmyyyy
	     new_date[0] = date_str[4];
	     new_date[1] = date_str[5];
	     new_date[2] = date_str[2];
	     new_date[3] = date_str[3];
	     new_date[4] = '1';
	     new_date[5] = '9';
	     new_date[6] = date_str[0];
	     new_date[7] = date_str[1];

	     printf("%c%c%c%c%c%c%c%c\t", new_date[0], new_date[1], new_date[2],
	     new_date[3], new_date[4], new_date[5], new_date[6], new_date[7]);
         }
	 
         // Record's Time
         if (master_file_record.time_frame == 'I') {
            fread(&data_file_record.time, sizeof(data_file_record.time), 1, df);
            if ( fmsbin2ieee((float *) &data_file_record.time, &record_time) == 0) {
               printf("%f\n", record_time);
            }
         }

	 // Record's Open
         if (((master_file_record.time_frame == 'D') && ((master_file_record.num_fields == 6) || (master_file_record.num_fields == 7) || (master_file_record.num_fields == 8))) || ((master_file_record.time_frame == 'I') && ((master_file_record.num_fields == 7) || (master_file_record.num_fields == 8)))) {
            fread(&data_file_record.open, sizeof(data_file_record.open), 1, df);
            if (fmsbin2ieee((float *) &data_file_record.open, &record_open) == 0 ) {
               printf("%f\t", record_open);
            }
         }

	 // Record's High
	 fread(&data_file_record.high, sizeof(data_file_record.high), 1, df);
         if ( fmsbin2ieee((float *) &data_file_record.high, &record_high) == 0) {
            printf("%f\t", record_high);
         }

	 // Record's Low
	 fread(&data_file_record.low, sizeof(data_file_record.low), 1, df);
         if ( fmsbin2ieee((float *) &data_file_record.low, &record_low) == 0) {
            printf("%f\t", record_low);
         }

	 // Record's Close
         fread(&data_file_record.close, sizeof(data_file_record.close), 1, df);
         if ( fmsbin2ieee((float *) &data_file_record.close, &record_close) == 0) {
            printf("%f\t", record_close);
         }

	 // Record's Volume
         fread(&data_file_record.volume, sizeof(data_file_record.volume), 1, df);
         if ( fmsbin2ieee((float *) &data_file_record.volume, &record_volume) == 0) {
            int volume = int(record_volume);
	    printf("%i", volume);
         }

	 // Record's Open Interest
         if (((master_file_record.time_frame == 'D') && (master_file_record.num_fields == 7)) || ((master_file_record.time_frame == 'I') && (master_file_record.num_fields == 8))) {
            fread(&data_file_record.op_int, sizeof(data_file_record.op_int), 1, df);
	    
	    /* The following code is currently not necessary but might be usefull one day...
	    
            if (fmsbin2ieee((float *) &data_file_record.op_int, &record_op_int) == 0) {
               printf("%f\t", record_op_int);
            }
	    
	    */
         }
         printf("\n");
      }
      return true;
   } else {
       return false;
   }
}

/******************************************************************************/
/*   MetaStockDataBase - Constructor                                          */
/******************************************************************************/

MetaStockDataBase::MetaStockDataBase() {
}

/******************************************************************************/
/*   MetaStockDataBase - Destructor                                           */
/******************************************************************************/

MetaStockDataBase::~MetaStockDataBase() {
}

/******************************************************************************/
/*   MetaStockDataBase - get_all_master_files :                               */
/*   return a list of all MetaStock master files found in a directory,        */
/*   with or without recursive scan.                                          */
/******************************************************************************/

char ** MetaStockDataBase::get_all_master_files(char *directory, bool recursive = false)
{
   DIR  *dir;
   struct dirent *entry;
   struct stat buf;
   char search[MAXPATHLEN], next_directory[MAXPATHLEN];

   /* Little things to do to have the same sort of path */
   if (!strcmp(&directory[strlen(directory)-1], "/"))
      strcpy(search, directory);
   else
      strcat(strcpy(search, directory), "/");

   /* Initialize directory with the directory we have */
   if ((dir = opendir(search)) == NULL) {
      printf("Error opening directory (%s).\n", search);
      return(NULL);
   }

   /* Scan all entries in the main directory or in its sub-directories to find all MetaStock Master file. */
   while((entry = readdir(dir)) != NULL)
   {
      if (!((!strcmp(entry->d_name, ".")) || (!strcmp(entry->d_name, "..")))) {
         strcat(strcat(next_directory, search), entry->d_name);
         if ((!stat(next_directory, &buf)) && (buf.st_mode & S_IFDIR) && (recursive)) {
            get_all_master_files(next_directory, recursive);
         } else {
            if (!strcasecmp(entry->d_name, "Master")) {

               /* Master file found in next_directory */
	       if (! resultats)
	       {
		   resultats = (char **) malloc(sizeof(void*) * 25);
		   taille_resultats = 25;
	       } else
	       {
		   if (master_file_id == taille_resultats)
		   {
		       taille_resultats += 25;
		       resultats = (char **) realloc(resultats, sizeof(void*) * taille_resultats);
		   }
	       }

	       resultats[master_file_id] = (char *) malloc((strlen(next_directory)+1)*sizeof(char));
               strcpy(resultats[master_file_id], next_directory);
	       
               master_file_id++;
            }
         }
	 next_directory[0] = '\0';
      }
   }
   if (closedir(dir) != 0) {
      printf("Error closing directory (%s).\n", search);
   }
   return(resultats);
}

/******************************************************************************/
/*   MetaStockDataBase - initialize :                                         */
/*   Set up the directory where all research should be located and initialize */
/*   our research with or without recursive scan                              */
/******************************************************************************/

bool MetaStockDataBase::initialize(char *directory, bool recursive = false)
{
    init_directory = directory;
    init_recursive = recursive;
    
    DIR  *dir;
    if ((dir = opendir(init_directory)) == NULL) {
	printf("Error opening directory (%s).\n", init_directory);
	return false;
    } else {
	return true;
    }
}

/******************************************************************************/
/*   MetaStockDataBase - get_quotes :                                         */
/*   Get all master files for the directory where our search is located and   */
/*   look into to check if the symbol we need is there. Then, get all quotes  */
/*   available from the .dat or .DAT file corresponding to the symbol.        */
/******************************************************************************/

void MetaStockDataBase::get_quotes(char *symbol)
{

    char **list_of_master_files = get_all_master_files(init_directory, init_recursive);
    int max = 0;
    
   if (list_of_master_files != NULL) {
      
      for (int i = 0; i < master_file_id; i++) {
	
	Master_file master_file;
        master_file.header = get_master_file_header(fopen(list_of_master_files[i],"r"));
	
	if (master_file.header.num_files <= 255) {
	    max = master_file.header.num_files;
	} else {
	    max = 255;
	}
	printf("Master file : %s\nNum files : %i\n", list_of_master_files[i], max);
	for (int j = 0; j < max; j++) {
	    printf("J : %i\n", j);
	    master_file.record = get_master_file_record(fopen(list_of_master_files[i],"r"),j);
	    printf("Symbol : %s\n", master_file.record.symbol);
/*	    char *symbol_record = (char *) (master_file.record.symbol);
	    char *ptr = strchr(symbol_record, ' ');
	    *ptr = '\0';
	    printf("%s\n", symbol_record);
	    
	    if (!strcmp(symbol, symbol_record)) {
	
		char path[MAXPATHLEN], new_path[MAXPATHLEN];
		char file_number[3];
		sprintf(file_number, "%u", master_file.record.file_num);
		strncat(path, list_of_master_files[i], (strlen(list_of_master_files[i]) - 6));
		strcat(strcat(path, "F"), file_number);
		
		// Try to read the .dat file, otherwise try to read the .DAT file
		if (read_dat_file(fopen(strcat(path, ".dat"),"r"), master_file.record) == false) {
		    read_dat_file(fopen(strcat(strncpy(new_path, path, (strlen(path) - 4)), ".DAT"),"r"), master_file.record);
		}
	    }
	    */
	}
        free(list_of_master_files[i]);
      }
      free(list_of_master_files);
   } else {
      printf("Master file not found.\n");
   }
}

/******************************************************************************/
/*   MetaStockDataBase : PRIVATE FUNCTIONS                                    */
/******************************************************************************/

/******************************************************************************/
/*   get_master_file_header will read and return the master file header       */
/******************************************************************************/

Master_file_header MetaStockDataBase::get_master_file_header(FILE *fp)
{
   Master_file_header record;
   if (fp != (FILE *)NULL)
   {
      fread(&record.num_files, sizeof(record.num_files), 1, fp);
      fread(&record.file_num, sizeof(record.file_num), 1, fp);
      fread(&record.zeroes, sizeof(char), 49, fp);
   }
   return(record);
}

/******************************************************************************/
/*   get_master_file_record will read and return any master file record       */
/******************************************************************************/

Master_file_record MetaStockDataBase::get_master_file_record(FILE *fp, int record_number)
{
   Master_file_header header_record;
   Master_file_record record;
   if (fp != (FILE *)NULL)
   {
      fseek(fp, (sizeof(header_record.num_files)+sizeof(header_record.file_num)+sizeof(header_record.zeroes)) + 53 * record_number, SEEK_SET);

      fread(&record.file_num, sizeof(record.file_num), 1, fp);
      fread(&record.file_type, sizeof(char), 2, fp);
      fread(&record.rec_len, sizeof(record.rec_len), 1, fp);
      fread(&record.num_fields, sizeof(record.num_fields), 1, fp);
      fread(&record.reserved1, sizeof(char), 2, fp);
      fread(&record.issue_name, sizeof(char), 16, fp);
      fread(&record.reserved2, sizeof(record.reserved2), 1, fp);
      fread(&record.CT_v2_8_flag, sizeof(record.CT_v2_8_flag), 1, fp);
      fread(&record.first_date, sizeof(record.first_date), 1, fp);
      fread(&record.last_date, sizeof(record.last_date), 1, fp);
      fread(&record.time_frame, sizeof(record.time_frame), 1, fp);
      fread(&record.ida_time, sizeof(record.ida_time), 1, fp);
      fread(&record.symbol, sizeof(char), 14, fp);
      fread(&record.reserved3, sizeof(record.reserved3), 1, fp);
      fread(&record.flag, sizeof(record.flag), 1, fp);
      fread(&record.reserved4, sizeof(record.reserved4), 1, fp);
   }
   return(record);
}

void usage(void) {

    printf("MetaStockReader (C) Fabien Fulhaber\n");
    printf("usage: MetaStockReader [r] directory symbol\n");
}

int main(int argc, char *argv[]) {

    // Set up a MetaStockDataBase object and initialize recursive to false
    MetaStockDataBase msdb;
    bool recursive = false;

    // Process all options specified by ARGV
    while ((argc > 1) && (argv[1][0] == '-')) {

	switch(argv[1][1]) {
	    case 'r':
		recursive = true;
		break;

	    default:
		usage();
	}
	++argv;
	--argc;
    }
    
    if (argc > 2) {

	// Initialize the MetaStockDataBase object according to the options
        // and parameters previously selected
	if (msdb.initialize(argv[1], recursive)) {

	    // Get quotes for the specified symbol
	    msdb.get_quotes(argv[2]);
	}
    } else {
	usage();
    }
    
    return 0;
}