Thứ Năm, 31 tháng 5, 2012

Đọc/ghi dữ liệu chứng khoán trong Metastock Files bằng C++


Phần mềm phân tích kĩ thuật Metastock của Reuters khá nổi tiếng. Tuy giao diện của Metastock không thể so sánh với các phần mềm phân tích kỹ thuật khác như AmiBroker,...nhưng với rất nhiều công cụ hữu ích Expert Advisors, Indicator Builder, Exhanced System Test, The Explorer, phần mềm đáp ứng khá đầy đủ yêu cầu của các Teachnical Analysis. Trong mục này, mình không trình bày cách viết các chỉ báo kĩ thuật sử dụng ngôn ngữ lập trình meta programming hay hướng dẫn sử dụng Metastock cơ bản. Bài viết hướng đến vấn đề giải quyết việc truy xuất dữ liệu của Metastock trong các Files (MASTER, EMASTER, XMASTER, xxx.DAT). Trên mạng, mình thấy có trang web http://www.trading-tools.com/index.htm cung cấp module cho phép truy cập dữ liệu dưới dạng SDK hỗ trợ nhiều ngôn ngữ lập trình từ Python, C++, C#, VB.NET....nhưng giá rất cao. Phiên bản dành cho Commercial buyers giá khoản 450 USD. Làm sao có thể truy cập dữ liệu mà không phải trả giá quá đắc???? Vấn đề này được trình bày bởi nhiều người. Tuy nhiên, mình thấy khá phức tạp và không được chi tiết lắm. Vì vậy, mình muốn trình bày một số bước giúp các anh chị nào muốn truy xuất dữ liệu của Metastock với một vài bước đơn giản.

1) Metastock sử dụng kiểu dữ liệu Float để lưu trữ các thông tin (DATE, OPEN, CLOSE, HIGH, LOW,VOLOME) liên quan đến giá chứng khoán. Tuy nhiên, đây là kiểu dữ liệu cũ của Microsoft không thể dùng thể hiện khi ta truy xuất từ file của Metastock. Vấn đề chuyển đổi qua lại giữa chuẩn Microsoft và IEEE mình đã sao chép và upload trong blog trước.

2) Cấu trúc hệ thống FILE của METASTOCK như thế nào?????
- Metastock sử dụng FILE (MASTER,EMASTER, XMASTER) để chứa thông tin về các mã chứng khoán. Cơ bản thông tin đó bao gồm: Mã chứng khoán, thông tin, ngày bắt đầu, ngày kết thúc, và quan trong nhất là "Fx.DAT" trong đó "x" chỉ đến FILE.DAT chứa thông tin thực sự của mã chứng khoán đó.
- Các FILE.DAT có cấu trúc(DATE, OPEN, CLOSE, HIGH, LOW,VOLOME) lưu trữ dữ liệu của một mã chứng khoán nào đó. Để biết được đây thực sự là dữ liệu giao dịch của cổ phiếu nào, chúng ta cần so sánh thứ tự của File.DAT này với Record tương ứng trong MASTER FILE.

DƯỚI ĐÂY LÀ CẤU TRÚC DỮ LIỆU CHO CÁC FILE:
- Metastock.h: chứa cấu trúc dữ liệu của MASTER, EMASTER, XMASTER, FILEx.DAT

#if !defined( METASTOCK_H )
#define METASTOCK_H

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

// MetaStock.h : header file

#define MetaStockPack 1

// Remember the original packing (probably 8)
#pragma pack( push, OriginalPack, MetaStockPack )

#define METASTOCK_MASTER_FILE "MASTER.DAT"
#define METASTOCK_EMASTER_FILE "EMASTER.DAT"
#define CSI_MASTER_FILE "MASTER"

#define METASTOCK_DATA_FILE_TEMPLATE "F%i.dat"
#define METASTOCK_X_DATA_FILE_TEMPLATE "F%i.mwd"

#define LAST_MASTER_F_NUMBER 255
#define UINT unsigned int
#define USHORT unsigned short
#define CHAR char
#define UCHAR unsigned char
#define FLOAT float
#define INT int

//--------------------------------------------------------------
// MASTER file description (the original 255 record format:
// floats are in Microsoft Basic format
// strings are padded with spaces, not null terminated
//--------------------------------------------------------------
struct MasterHeader {
    USHORT totalFiles; // Number of files master contains
    USHORT lastFNumber; // Next file number to use (highest F# used)
    CHAR padding[45];
};

typedef struct MasterRecord {  
    UCHAR fileFNumber; // File #, i.e., F#
    CHAR fileType[2]; // CT file type = 0'e' (5 or 7 flds)
    UCHAR recordLength; // Record length in bytes (4 x num_fields)
    UCHAR totalFields; // Number of 4-byte fields in each record
    CHAR padding1[2];
    CHAR description[16]; // Stock or futures market name
    CHAR        descriptionEnd; //
    CHAR version28; // If CT ver. 2.8, 'Y'; o.w., anything else
    FLOAT firstDate; // yymmdd
    FLOAT lastDate; //
    CHAR period; // Data format: 'I'(IDA)/'W'/'Q'/'D'/'M'/'Y'
    USHORT intraDayTimeBase; // intraday (IDA) time base
    CHAR symbol[14]; // Stock symbol
    CHAR symbolEnd; // MetaStock reserved2: must be a space
    CHAR flag; // ' ' or '*' for autorun
    CHAR padding4; //
} MasterRecord, *MasterRecordPtr;

typedef struct MasterFile {

MasterHeader header;
MasterRecord records[4];

} MasterFile, *MasterFilePtr;
//--------------------------------------------------------------
// EMASTER file description:
// floats are in IEEE format
// strings are padded with nulls
//--------------------------------------------------------------

struct EMasterHeader {
    USHORT totalFiles; // number of files in emaster */
    USHORT file_num; // last (highest) file number */
    CHAR stuff[188];
};

typedef struct EMasterRecord {
    CHAR asc30[2];    // "30";
    UCHAR fileFNumber; // File number F#
    CHAR fill1[3];
    UCHAR totalFields; // number of 4-byte data fields
    CHAR fill2[2];
    CHAR flag; // ' ' or '*' for autorun
    CHAR fill3;
    CHAR symbol[13]; // Stock symbol
    CHAR symbolEnd; // Stock symbol
    CHAR fill4[7];
    CHAR description[15];// Stock or futures name
    CHAR descriptionEnd; // End
    CHAR fill5[12];
    CHAR period; // Data format: 'D','W', 'M', etc.
    CHAR fill6[3];
    FLOAT firstDate;    // Date - YYMMDD
    CHAR fill7[4];
    FLOAT lastDate; // Date - YYMMDD
    CHAR fill8[116];
} EMasterRecord, *EMasterRecordPtr;

typedef struct EMasterFile {

EMasterHeader header;
EMasterRecord records[4];

} EMasterFile, *EMasterFilePtr;
//--------------------------------------------------------------
// XMASTER file description (150 byte records):
// no floats
// strings are padded with nulls
//--------------------------------------------------------------

struct XMasterHeader {
// OFS - Decimal Offset
CHAR char5D; // 000 - 0x5D
CHAR charFE; // 001 - 0xFE
CHAR xmChars[2]; // 002 - "XM"
CHAR pad[6];
USHORT totalFiles; // 010 - Number of files master contains
CHAR pad2[2];
USHORT totalFiles2; // 014 - Number of files master contains
CHAR pad3[2];
USHORT lastFNumber; // 018 - Next file number to use (highest F# used)
CHAR padding[130];
};

typedef struct XMasterRecord {
CHAR onePad; // 000 - 0x01
CHAR symbol[15]; // 001 - ASCII Symbol (zero terminated)
CHAR description[32]; // 016 - ASCII Description
CHAR pad[14];
CHAR period; // 062 - Data period: 'D','W', 'M', etc.
CHAR pad2[2];
USHORT fileFNumber; // 065 - File number F#
CHAR pad3[13];
INT firstDate; // 080 - First Data Date
CHAR pad4[20];
INT lastDate; // 104 - Last Data Date
INT firstTradingDate; // 108 - Start of Trading for Instrument?
INT lastDate2; // 112 - Start Date?
CHAR pad5[34];
} XMasterRecord, *XMasterRecordPtr;

typedef struct XMasterFile {

XMasterHeader header;
XMasterRecord records[4];

} XMasterFile, *XMasterFilePtr;

//-----------------------------------------------------------------
// Seven-field Data File Description


// Data Header
//-----------------------------------------------------------------
struct MetaStockDataHeader {
    USHORT dontUse_TotalRecords;
                                    // The number of records. NOTE: This is not filled in by CSI so don't use.
    USHORT lastRecord;  
                                   // The last record in the file, NOTE: The header is one, the records start at two.
    CHAR padding[24]; // Pad to get 28 bytes
};

// Data Record
typedef struct MetaStockRecord {
     CHAR         date[4]; // NOTE: Add these floats are in the bogus old MS Basic format.
    CHAR open[4]; // cac phan tu nay o dinh dang FLoat nhung theo chuan Microsoft
    CHAR high[4]; // do do de co the su dung duoc can chuyen sang dinh dang IEEE Float
    CHAR low[4];
    CHAR close[4];
    CHAR volume[4];
    CHAR openInterest[4];
} MetaStockRecord, *MetaStockRecordPtr;

typedef struct MetaStockDataFile {

MetaStockDataHeader header;
MetaStockRecord records[4];

} MetaStockDataFile, *MetaStockFilePtr;

// Restore the original packing
#pragma pack( pop, OriginalPack )
#endif // !defined( METASTOCK_H )


HÀM CHUYỂN ĐỔI TỪ ĐỊNH DẠNG FLOAT CỦA MICROSOFT SANG ĐỊNH DẠNG IEEE
float ConvertMBFToFloat(char* bytArray)
{
unsigned int *temp; // point to merory containing value
unsigned int valtemp;
// tranform CHAR ARRAY to UNSIGNED INT
temp = (unsigned int*) bytArray;
valtemp = *temp; // copy this value to valtemp
//Do shift some bits to change MBF to IEEE Float format
valtemp = (((valtemp - 0x02000000) & 0xFF000000) >> 1) |
        ((valtemp & 0x00800000) << 8) |
        (valtemp & 0x007FFFFF);

// tranform UNSIGNED INT to FLOAT
float* fresult = (float*)&valtemp;
return *fresult;
}
ĐỌC EMASTER FILE VÀ XUẤT THÔNG TIN MÃ CHỨNG KHOÁN/ NGÀY BẮT ĐẦU/ NGÀY KẾT THÚC:
void main ()
{
char          s_Buffer[BUFFER_SIZE];
FILE*                               masterFile;
EMasterFilePtr               masterPtr;

EMasterRecordPtr         masterRecordPtr;
int                                     fileIndex;


if( fopen_s( &masterFile, "EMASTER", "r" ) == 0 )

{
      // Attempt to read in 25 characters 
      numread = fread( s_Buffer, sizeof( char ),  BUFFER_SIZE , masterFile );
      printf( "Number of items read = %d\n", numread );
      printf( "Contents of buffer = %.25s\n",s_Buffer );
      fclose(masterFile);

}


// Get a pointer in the correct format.
masterPtr = (EMasterFilePtr) s_Buffer ;

for ( fileIndex = 0; fileIndex < masterPtr->header.totalFiles; fileIndex ++ )
{
// Get a pointer to the record.
masterRecordPtr = &masterPtr->records[ fileIndex ];
       
        //-------------------------------------------------------------------------
        // do what information you need at this point
        //-------------------------------------------------------------------------
        printf( "Stock code = %s\n", masterRecordPtr->symbol );
        printf( "First date = %.f\n", masterRecordPtr->firstdate);
        printf( "Last date = %.f\n", masterRecordPtr->lastdate);
}
}

ĐỌC Fxx.DAT  FILE VÀ XUẤT THÔNG TIN GIAO DICH CHỨNG KHOÁN:


void main ()
{
char          s_Buffer[BUFFER_SIZE];
FILE* stockFile;

MetaStockFilePtr metaStockFilePtr;
MetaStockRecordPtr metaRecordPtr;

int                                     fileIndex;



//Read Stock Data in F1.Dat
if( fopen_s(&stockFile, "F1.DAT", "r" ) == 0 )
{
       // Attempt to read in 25 characters 
      numread = fread( s_Buffer, sizeof( char ),
BUFFER_SIZE

, stockFile );
      printf( "Number of items read = %d\n", numread );
      printf( "Contents of buffer = %.25s\n",s_Buffer );
      fclose(stockFile);
}

// Get a pointer in the correct format.
 metaStockFilePtr = (MetaStockFilePtr) s_Buffer;

for ( fileIndex = 0; fileIndex < metaStockFilePtr->header.lastRecord; fileIndex ++ )
{
// Get a pointer to the record.
metaRecordPtr = &metaStockFilePtr->records[ fileIndex ];


        //-------------------------------------------------------------------------
        // do what information you need at this point
        //-------------------------------------------------------------------------
        float open, close, high, low, date;
        open  = ConvertMBFToFloat(metaRecordPtr->open);
        high = ConvertMBFToFloat(metaRecordPtr->high);
        close = ConvertMBFToFloat(metaRecordPtr->close);
        low =ConvertMBFToFloat(metaRecordPtr->low);
        date = ConvertMBFToFloat(metaRecordPtr->date);
        printf( "Date: %f  with OPEN: %f, HIGH: %f, LOW: %f, CLOSE: %f", day, open, high,      low, close);
}
}

2 nhận xét:

  1. Hay lắm bạn, muốn hợp tác với chúng tôi không?

    Trả lờiXóa
  2. Mình cũng biết anh Adwin (chuyên gia về Phân tích kỹ thuật). Không biết liên lạc với anh thế nào ah? Số điện thoại em: 090.806.2900 Anh em có dịp Cafe xem có gì cùng nhau làm nhé.

    Thanks,
    Pham Duc Toan

    Trả lờiXóa