#ifndef INTRADAY_RECORD_H #define INTRADAY_RECORD_H /********************************************************************/ // s_IntradayRecord //Special values used for s_IntradayRecord::Open const float SINGLE_TRADE_WITH_BID_ASK = 0.0F; const float FIRST_SUB_TRADE_OF_UNBUNDLED_TRADE_VALUE = -1.99900095e+37F; const float LAST_SUB_TRADE_OF_UNBUNDLED_TRADE_VALUE = -1.99900197e+37F; struct s_IntradayRecord { //--- Static Members --------------------------------------------- //--- Members ---------------------------------------------------- SCDateTimeMS DateTime; float Open; float High; float Low; float Close; uint32_t NumTrades; uint32_t TotalVolume; uint32_t BidVolume; uint32_t AskVolume; //--- Methods ---------------------------------------------------- s_IntradayRecord(); s_IntradayRecord(int Value); bool operator == (const s_IntradayRecord& Record) const; s_IntradayRecord& operator = (const s_IntradayRecord& Record); s_IntradayRecord& operator += (const float Amount); s_IntradayRecord& operator *= (const float Multiplier); s_IntradayRecord& operator /= (const float Divisor); void AddAdjustment ( const float Amount , const bool AdjustZeroValues ); bool IsEmpty() const; void Clear(); void ClearOpenFlags(); void Fix(); bool IsSingleTradeWithBidAsk() const; bool IsFirstSubTradeOfUnbundledTrade() const; bool IsLastSubTradeOfUnbundledTrade() const; bool IsFirstOrLastSubTradeOfUnbundledTrade() const; bool IsBidAskUpdateOnly() const; float GetOpen() const; float GetHigh() const; float GetLow() const; float GetClose() const; float GetBidPrice() const; float GetAskPrice() const; }; /********************************************************************/ // s_Header struct s_IntradayFileHeader { static const uint32_t UNIQUE_HEADER_ID = 0x44494353; // "SCID" uint32_t FileTypeUniqueHeaderID; // "SCID" uint32_t HeaderSize; uint32_t RecordSize; uint16_t Version; uint16_t Unused1; uint32_t Unused2; char Reserve[36]; s_IntradayFileHeader() : FileTypeUniqueHeaderID(UNIQUE_HEADER_ID) , HeaderSize(sizeof(s_IntradayFileHeader)) , RecordSize(sizeof(s_IntradayRecord)) , Version(1) , Unused1(0) , Unused2(0) { memset(Reserve, 0, sizeof(Reserve)); } }; /****************************************************************************/ // s_IntradayRecord /*==========================================================================*/ inline s_IntradayRecord::s_IntradayRecord() { Clear(); } /*============================================================================ This constructor is to support using this structure as an c_SCArray element. ----------------------------------------------------------------------------*/ inline s_IntradayRecord::s_IntradayRecord(int Value) { Clear(); } /*==========================================================================*/ inline bool s_IntradayRecord::operator == (const s_IntradayRecord& Record ) const { return memcmp(this, &Record, sizeof(s_IntradayRecord)) == 0; } /*==========================================================================*/ inline s_IntradayRecord& s_IntradayRecord::operator = (const s_IntradayRecord& Record ) { if (&Record == this) return *this; memcpy(this, &Record, sizeof(s_IntradayRecord)); return *this; } /*==========================================================================*/ inline s_IntradayRecord& s_IntradayRecord::operator += (const float Amount) { if (!IsSingleTradeWithBidAsk()) Open += Amount; High += Amount; Low += Amount; Close += Amount; return *this; } /*==========================================================================*/ inline s_IntradayRecord& s_IntradayRecord::operator *= (const float Multiplier) { if (!IsSingleTradeWithBidAsk()) Open *= Multiplier; High *= Multiplier; Low *= Multiplier; Close *= Multiplier; return *this; } /*==========================================================================*/ inline s_IntradayRecord& s_IntradayRecord::operator /= (const float Divisor) { if (!IsSingleTradeWithBidAsk()) Open /= Divisor; High /= Divisor; Low /= Divisor; Close /= Divisor; return *this; } /*============================================================================ Adds the given Amount to the prices, so long as the prices are non-zero, or AdjustZeroValues is true. ----------------------------------------------------------------------------*/ inline void s_IntradayRecord::AddAdjustment (const float Amount , const bool AdjustZeroValues ) { if (!IsSingleTradeWithBidAsk()) { if (Open != 0.0f || AdjustZeroValues) Open += Amount; } if (High != 0.0f || AdjustZeroValues) High += Amount; if (Low != 0.0f || AdjustZeroValues) Low += Amount; if (Close != 0.0f || AdjustZeroValues) Close += Amount; } /*==========================================================================*/ inline bool s_IntradayRecord::IsEmpty() const { return DateTime == 0.0 && Open == 0.0f && High == 0.0f && Low == 0.0f && Close == 0.0f && NumTrades == 0 && TotalVolume == 0; } /*==========================================================================*/ inline void s_IntradayRecord::Clear() { DateTime = 0.0; Open = 0.0f; High = 0.0f; Low = 0.0f; Close = 0.0f; NumTrades = 0; TotalVolume = 0; BidVolume = 0; AskVolume = 0; } /*==========================================================================*/ inline void s_IntradayRecord::ClearOpenFlags() { Open = 0.0f; } /*============================================================================ This function fixes any data that looks erroneous. ----------------------------------------------------------------------------*/ inline void s_IntradayRecord::Fix() { if (NumTrades > INT_MAX) NumTrades = 0; if (TotalVolume > INT_MAX) TotalVolume = 0; if (BidVolume > INT_MAX) BidVolume = 0; if (AskVolume > INT_MAX) AskVolume = 0; } /*==========================================================================*/ inline bool s_IntradayRecord::IsSingleTradeWithBidAsk() const { return NumTrades == 1 && (Open == 0.0 || Open == FIRST_SUB_TRADE_OF_UNBUNDLED_TRADE_VALUE || Open == LAST_SUB_TRADE_OF_UNBUNDLED_TRADE_VALUE ); } /*==========================================================================*/ inline bool s_IntradayRecord::IsFirstSubTradeOfUnbundledTrade() const { return (Open == FIRST_SUB_TRADE_OF_UNBUNDLED_TRADE_VALUE); } /*==========================================================================*/ inline bool s_IntradayRecord::IsLastSubTradeOfUnbundledTrade() const { return (Open == LAST_SUB_TRADE_OF_UNBUNDLED_TRADE_VALUE); } /*==========================================================================*/ inline bool s_IntradayRecord::IsFirstOrLastSubTradeOfUnbundledTrade() const { return Open == FIRST_SUB_TRADE_OF_UNBUNDLED_TRADE_VALUE || Open == LAST_SUB_TRADE_OF_UNBUNDLED_TRADE_VALUE; } /*==========================================================================*/ inline bool s_IntradayRecord::IsBidAskUpdateOnly() const { return NumTrades == 1 && TotalVolume == 0 && Open == 0.0 && High != 0.0 && Low != 0.0; } /*==========================================================================*/ inline float s_IntradayRecord::GetOpen() const { if (IsSingleTradeWithBidAsk()) return Close; return Open; } /*==========================================================================*/ inline float s_IntradayRecord::GetHigh() const { if (IsSingleTradeWithBidAsk()) return Close; return High; } /*==========================================================================*/ inline float s_IntradayRecord::GetLow() const { if (IsSingleTradeWithBidAsk()) return Close; return Low; } /*==========================================================================*/ inline float s_IntradayRecord::GetClose() const { return Close; } /*==========================================================================*/ inline float s_IntradayRecord::GetBidPrice() const { if (!IsSingleTradeWithBidAsk()) return 0.0f; return Low; } /*==========================================================================*/ inline float s_IntradayRecord::GetAskPrice() const { if (!IsSingleTradeWithBidAsk()) return 0.0f; return High; } #endif