diff --git a/eclientsocket.go b/eclientsocket.go index fd265c2..7fc52e5 100644 --- a/eclientsocket.go +++ b/eclientsocket.go @@ -132,6 +132,7 @@ const ( mUpdateDisplayGroup = 69 mUnsubscribeFromGroupEvents = 70 mStartAPI = 71 + mRequestSecDefOptParams = 78 ) type serverHandshake struct { @@ -1363,6 +1364,40 @@ func (c *CancelPositions) code() OutgoingMessageID { return mCancelPositions func (c *CancelPositions) version() int64 { return 1 } func (c *CancelPositions) write(b *bytes.Buffer) error { return nil } +// RequestSecDefOptParams is equivalent of IB API EClientSocket.reqSecDefOptParams +type RequestSecDefOptParams struct { + id int64 + Symbol string + Exchange string + SecType string + ContractId int64 +} + +func (r *RequestSecDefOptParams) SetID(id int64) { r.id = id } + +func (r *RequestSecDefOptParams) ID() int64 { return r.id } +func (r *RequestSecDefOptParams) code() OutgoingMessageID { return mRequestSecDefOptParams } +func (r *RequestSecDefOptParams) version() int64 { return -1 } +func (r *RequestSecDefOptParams) write(b *bytes.Buffer) error { + if err := writeInt(b, r.id); err != nil { + return err + } + + if err := writeString(b, r.Symbol); err != nil { + return err + } + + if err := writeString(b, r.Exchange); err != nil { + return err + } + + if err := writeString(b, r.SecType); err != nil { + return err + } + + return writeInt(b, r.ContractId) +} + // RequestAccountSummary is equivalent of IB API EClientSocket.reqAccountSummary() type RequestAccountSummary struct { id int64 diff --git a/engine.go b/engine.go index 4b672a6..dc27a32 100644 --- a/engine.go +++ b/engine.go @@ -538,7 +538,11 @@ func (v *header) write(b *bytes.Buffer) error { if err := writeInt(b, v.code); err != nil { return err } - return writeInt(b, v.version) + + if v.version != -1 { + return writeInt(b, v.version) + } + return nil } func (v *header) read(b *bufio.Reader) error { @@ -547,7 +551,13 @@ func (v *header) read(b *bufio.Reader) error { if v.code, err = readInt(b); err != nil { return err } - v.version, err = readInt(b) + + if msgHasVersion(v.code) { + v.version, err = readInt(b) + } else { + v.version = -1 + } + return err } diff --git a/ereader.go b/ereader.go index 0bc25e6..a77eb65 100644 --- a/ereader.go +++ b/ereader.go @@ -14,49 +14,51 @@ type IncomingMessageID int64 // Message types enum const ( - mTickPrice IncomingMessageID = 1 - mTickSize = 2 - mOrderStatus = 3 - mErrorMessage = 4 - mOpenOrder = 5 - mAccountValue = 6 - mPortfolioValue = 7 - mAccountUpdateTime = 8 - mNextValidID = 9 - mContractData = 10 - mExecutionData = 11 - mMarketDepth = 12 - mMarketDepthL2 = 13 - mNewsBulletins = 14 - mManagedAccounts = 15 - mReceiveFA = 16 - mHistoricalData = 17 - mBondContractData = 18 - mScannerParameters = 19 - mScannerData = 20 - mTickOptionComputation = 21 - mTickGeneric = 45 - mTickString = 46 - mTickEFP = 47 - mCurrentTime = 49 - mRealtimeBars = 50 - mFundamentalData = 51 - mContractDataEnd = 52 - mOpenOrderEnd = 53 - mAccountDownloadEnd = 54 - mExecutionDataEnd = 55 - mDeltaNeutralValidation = 56 - mTickSnapshotEnd = 57 - mMarketDataType = 58 - mCommissionReport = 59 - mPosition = 61 - mPositionEnd = 62 - mAccountSummary = 63 - mAccountSummaryEnd = 64 - mVerifyMessageAPI = 65 - mVerifyCompleted = 66 - mDisplayGroupList = 67 - mDisplayGroupUpdated = 68 + mTickPrice IncomingMessageID = 1 + mTickSize = 2 + mOrderStatus = 3 + mErrorMessage = 4 + mOpenOrder = 5 + mAccountValue = 6 + mPortfolioValue = 7 + mAccountUpdateTime = 8 + mNextValidID = 9 + mContractData = 10 + mExecutionData = 11 + mMarketDepth = 12 + mMarketDepthL2 = 13 + mNewsBulletins = 14 + mManagedAccounts = 15 + mReceiveFA = 16 + mHistoricalData = 17 + mBondContractData = 18 + mScannerParameters = 19 + mScannerData = 20 + mTickOptionComputation = 21 + mTickGeneric = 45 + mTickString = 46 + mTickEFP = 47 + mCurrentTime = 49 + mRealtimeBars = 50 + mFundamentalData = 51 + mContractDataEnd = 52 + mOpenOrderEnd = 53 + mAccountDownloadEnd = 54 + mExecutionDataEnd = 55 + mDeltaNeutralValidation = 56 + mTickSnapshotEnd = 57 + mMarketDataType = 58 + mCommissionReport = 59 + mPosition = 61 + mPositionEnd = 62 + mAccountSummary = 63 + mAccountSummaryEnd = 64 + mVerifyMessageAPI = 65 + mVerifyCompleted = 66 + mDisplayGroupList = 67 + mDisplayGroupUpdated = 68 + mSecurityDefinitionOptionParameter = 75 + mSecurityDefinitionOptionParameterEnd = 76 ) // code2Msg is equivalent of EReader.processMsg() switch statement cases. @@ -148,12 +150,28 @@ func code2Msg(code int64) (r Reply, err error) { r = &DisplayGroupList{} case int64(mDisplayGroupUpdated): r = &DisplayGroupUpdated{} + case int64(mSecurityDefinitionOptionParameter): + r = &SecurityDefinitionOptionParameter{} + case int64(mSecurityDefinitionOptionParameterEnd): + r = &SecurityDefinitionOptionParameterEnd{} default: err = fmt.Errorf("Unsupported incoming message type %d", code) } return r, err } +func msgHasVersion(code int64) bool { + switch code { + case int64(mSecurityDefinitionOptionParameter): + return false + case int64(mSecurityDefinitionOptionParameterEnd): + return false + default: + } + + return true +} + // TickPrice holds bid, ask, last, etc. price information type TickPrice struct { id int64 @@ -1893,3 +1911,80 @@ func (d *DisplayGroupUpdated) read(b *bufio.Reader) (err error) { d.ContractInfo, err = readString(b) return err } + +type SecurityDefinitionOptionParameter struct { + id int64 + Exchange string + ContractId int64 + TradingClass string + Multiplier string + Expirations []string + Strikes []float64 +} + +func (s *SecurityDefinitionOptionParameter) ID() int64 { return s.id } +func (s *SecurityDefinitionOptionParameter) code() IncomingMessageID { + return mSecurityDefinitionOptionParameter +} +func (s *SecurityDefinitionOptionParameter) read(b *bufio.Reader) (err error) { + if s.id, err = readInt(b); err != nil { + return err + } + + if s.Exchange, err = readString(b); err != nil { + return err + } + + if s.ContractId, err = readInt(b); err != nil { + return err + } + + if s.TradingClass, err = readString(b); err != nil { + return err + } + + if s.Multiplier, err = readString(b); err != nil { + return err + } + + numExpirations, err := readInt(b) + if err != nil { + return err + } + + s.Expirations = make([]string, numExpirations) + for i := int64(0); i < numExpirations; i += 1 { + if s.Expirations[i], err = readString(b); err != nil { + return err + } + } + + numStrikes, err := readInt(b) + if err != nil { + return err + } + + s.Strikes = make([]float64, numStrikes) + for i := int64(0); i < numStrikes; i += 1 { + if s.Strikes[i], err = readFloat(b); err != nil { + return err + } + } + + return nil + +} + +type SecurityDefinitionOptionParameterEnd struct { + id int64 +} + +// ID contains the TWS "reqId", which is used for reply correlation. +func (s *SecurityDefinitionOptionParameterEnd) ID() int64 { return s.id } +func (s *SecurityDefinitionOptionParameterEnd) code() IncomingMessageID { + return mSecurityDefinitionOptionParameterEnd +} +func (s *SecurityDefinitionOptionParameterEnd) read(b *bufio.Reader) (err error) { + s.id, err = readInt(b) + return err +}