package response import ( "encoding/xml" "time" "log" "math" "regexp" ) type ExecutionEvent struct { XMLName xml.Name `xml:"order"` OrderEvent } type Orders struct { XMLName xml.Name `xml:"orders"` Data []*OrderEvent `xml:"page>order"` HasMoreResults bool `xml:"hasMoreResults"` CorrelationId int64 `xml:"correlationId"` } //基本流程是:客户在我们的matcher里面 //添加order //cancel order //close order //matcher 会发送对应的消息给mtf //mtf 根据orderId 找到对应的msg //然后找到对应的client,更新account的信息 //并通知给client //matcher 和 外界交互的标示是 orderId //这个order id 联系原始的msg //在配对表中的订单信息 type Order struct { XMLName xml.Name `xml:"order"` TimeInForce string `xml:"timeInForce"` InstructionId string `xml:"instructionId"` OriginalInstructionId string `xml:"originalInstructionId,omitempty"` OrderId string `xml:"orderId"` OpeningOrderId string `xml:"openingOrderId,omitempty"` AccountId int64 `xml:"accountId"` InstrumentId int64 `xml:"instrumentId"` Quantity float64 `xml:"quantity"` FilledQuantity float64 `xml:"matchedQuantity"` MatchedCost float64 `xml:"matchedCost"` CancelledQuantity float64 `xml:"cancelledQuantity"` LimitPrice float64 `xml:"price,omitempty"` Timestamp time.Time `xml:"-"` TimestampStr string `xml:"timestamp"` OrderType string `xml:"orderType"` OpenQuantity float64 `xml:"openQuantity"` OpenCost float64 `xml:"openCost"` CumulativeCost float64 `xml:"cumulativeCost"` Commission float64 `xml:"commission"` StopReferencePrice float64 `xml:"stopReferencePrice"` StopLossOffset float64 `xml:"stopLossOffset,omitempty"` StopProfitOffset float64 `xml:"stopProfitOffset,omitempty"` Margin float64 `xml:"-"` Profit float64 `xml:"-"` CurPrice float64 `xml:"-"` Currency string `xml:"-"` } func (order *Order) GetQuantity() float64 { dt := order.Quantity - order.FilledQuantity - order.CancelledQuantity return dt } //配对:从 buy 到 sell func (order *Order) MatchQuantity(other *Order) float64 { dt := order.Quantity - order.FilledQuantity - order.CancelledQuantity dt2 := other.Quantity - other.FilledQuantity - other.CancelledQuantity //dt >= 0 dt2 <= 0 //dt >= dt2 if math.Abs(dt + dt2) >= 1e-9 { order.FilledQuantity -= dt2 other.FilledQuantity += dt2 return -dt2 } order.FilledQuantity += dt other.FilledQuantity -= dt return dt } //一次配对的信息 type Execution struct { MatchId int64 `xml:"-"` Order *Order `xml:"-"` Price float64 `xml:"price,omitempty"` Quantity float64 `xml:"quantity,omitempty"` } type OrderEvent struct { XMLName xml.Name `xml:"order"` Order ExecutionId int64 `xml:"executions>executionId,omitempty"` Executions []Execution `xml:"executions>execution,omitempty"` Cancelleds []Execution `xml:"executions>orderCancelled,omitempty"` } func (this *OrderEvent) GetId() string { return this.InstructionId } func (this *OrderEvent) SetId(id string) { this.InstructionId = id } func (this *OrderEvent) SetAccountId(id int64) { this.AccountId = id } func (this *OrderEvent) Clone() interface{} { tmp := *this return &tmp } // //1448872301.313011 func NewOrderEvent(eventData string) (*OrderEvent, *ExecutionEvent) { r := OrderEvent{} data := replaceEmptyTag([]byte(eventData)) err := xml.Unmarshal(data, &r) if err != nil { log.Println(eventData, err) return nil, nil } r.Timestamp = parseTime(r.TimestampStr) if r.ExecutionId != 0 { return &r, &ExecutionEvent{xml.Name{}, r} } return &r, nil } //挂单 func (order *OrderEvent) IsExecution() bool { if order.ExecutionId == 0 { return false } if len(order.Executions) > 0 && sameSign(order.Quantity, order.Executions[0].Quantity) { return true } if len(order.Cancelleds) > 0 && sameSign(order.Quantity, order.Cancelleds[0].Quantity) { return true } return false } func sameSign(a float64, b float64) bool { if a == b { return true } if a > 0 && b > 0 { return true } if a <0 && b < 0 { return true } return false } func (order *OrderEvent) IsWorking() bool { dt := order.Quantity - order.FilledQuantity - order.CancelledQuantity return dt != 0 && (OrderType(order.OrderType) == "LIMIT" || OrderType(order.OrderType) == "STOP") } func (order *OrderEvent) IsStopProft() bool { if OrderType(order.OrderType) == "STOP_PROFIT_ORDER" || OrderType(order.OrderType) == "STOP_LOSS_ORDER" { return true } return false } //可以从活动列表中删除的订单 func (order *OrderEvent) IsClosed() bool { dt := order.Quantity - order.FilledQuantity - order.CancelledQuantity //log.Println(dt, order.OpenQuantity, dt == 0 && order.OpenQuantity == 0) if dt == 0 && order.OpenQuantity == 0 { return true } return false } func (order *OrderEvent) SetClosed() { order.OpenQuantity = 0 order.FilledQuantity = order.Quantity - order.CancelledQuantity } func parseTime(t string) time.Time { t1, err := time.Parse("2006-01-02T15:04:05", t) if err != nil { return time.Time{} } return t1 } func OrderType(s string) string { switch s { case "STOP_COMPOUND_PRICE_LIMIT", "PRICE_LIMIT": return "LIMIT" case "STOP_COMPOUND_MARKET", "MARKET_ORDER": return "MARKET" case "STOP_ORDER": return "STOP" case "MARKET", "LIMIT", "CLOSE_OUT_ORDER", "CLOSE_OUT_ORDER_POSITION", "CLOSE_OUT_POSITION", "STOP_LOSS_MARKET_ORDER", "STOP_PROFIT_LIMIT_ORDER", "STOP_PROFIT_ORDER", "STOP_LOSS_ORDER", "SETTLEMENT_ORDER", "OFF_ORDERBOOK", "REVERSAL": return s } return "UNKNOWN" } func TimeInForce(s string) string { switch s { case "FillOrKill", "ImmediateOrCancel", "GoodForDay", "GoodTilCancelled": return s } return "Unknown" } type CompletedOrder struct { XMLName xml.Name `xml:"completedOrder"` OrderId string `xml:"orderId"` InstrumentId int64 `xml:"instrumentId"` OrderType string `xml:"orderType"` TimestampStr string `xml:"timestamp"` Timestamp time.Time `xml:"-"` RealisedProfit float64 `xml:"realisedProfit,omitempty"` Commission float64 `xml:"commission"` Quantity float64 `xml:"quantity"` FilledQuantity float64 `xml:"filledQuantity"` FilledCost float64 `xml:"filledCost"` CancelledQuantity float64 `xml:"cancelledQuantity"` Price float64 `xml:"price"` Status string `xml:"status"` } type CompletedOrders struct { XMLName xml.Name `xml:"res"` Data []*CompletedOrder `xml:"body>completedOrders>completedOrder"` HasMoreResults bool `xml:"body>hasMoreResults"` } var emptyTag = regexp.MustCompile("<[^/]+/>") func replaceEmptyTag(data []byte) []byte { return emptyTag.ReplaceAll(data, []byte("")) } func NewCompletedOrders(eventData string) (*CompletedOrders, error) { r := CompletedOrders{} data := []byte(eventData) data = replaceEmptyTag(data) err := xml.Unmarshal(data, &r) if err != nil { return nil, err } for i := 0; i < len(r.Data); i++ { r.Data[i].Timestamp = parseTime(r.Data[i].TimestampStr) } return &r, nil } type Activity struct { Description string `xml:"description"` TimestampStr string `xml:"timestamp"` Timestamp time.Time `xml:"-"` Username string `xml:"username"` } type Activitys struct { XMLName xml.Name `xml:"res"` Data []*Activity `xml:"body>activity>orderEvent"` HasMoreResults bool `xml:"body>hasMoreResults"` } func NewActivitys(eventData string) (*Activitys, error) { r := Activitys{} data := []byte(eventData) err := xml.Unmarshal(data, &r) if err != nil { return nil, err } for i := 0; i < len(r.Data); i++ { r.Data[i].Timestamp = parseTime(r.Data[i].TimestampStr) } return &r, nil } type AccountStatement struct { Id int64 `xml:"id"` TimestampStr string `xml:"timestamp"` Timestamp time.Time `xml:"-"` CorrelationId int64 `xml:"correlationId"` InstrumentId int64 `xml:"instrumentId"` InstrumentName string `xml:"instrumentName"` VolumeWeightedAvgPrice float64 `xml:"volumeWeightedAvgPrice"` MatchedQuantity float64 `xml:"matchedQuantity"` UnitPrice float64 `xml:"unitPrice"` Type string `xml:"type"` Currency string `xml:"currency"` Amount float64 `xml:"amount"` Quantity float64 `xml:"quantity"` OrderId string `xml:"orderId,omitempty"` MinimumCommission float64 `xml:"minimumCommission,omitempty"` CommissionRate float64 `xml:"commissionRate,omitempty"` OpeningPrice float64 `xml:"openingPrice,omitempty"` OpeningOrderId string `xml:"openingOrderId,omitempty"` ClosingOrderId string `xml:"closingOrderId,omitempty"` ClosingPrice float64 `xml:"closingPrice,omitempty"` OpenQuantity float64 `xml:"openQuantity,omitempty"` FundingSpread float64 `xml:"fundingSpread,omitempty"` } type AccountStatements struct { XMLName xml.Name `xml:"res"` Data []*AccountStatement `xml:"body>transactions>transaction"` HasMoreResults bool `xml:"body>hasMoreResults"` } func NewAccountStatements(eventData string) (*AccountStatements, error) { r := AccountStatements{} data := []byte(eventData) err := xml.Unmarshal(data, &r) if err != nil { return nil, err } for i := 0; i < len(r.Data); i++ { r.Data[i].Timestamp = parseTime(r.Data[i].TimestampStr) } return &r, nil } //OrderTransactions type OrderTransactions struct { XMLName xml.Name `xml:"res"` Data []*OrderTransaction `xml:"body>orderTransactions>orderTransaction"` HasMoreResults bool `xml:"body>hasMoreResults"` } type OrderTransaction struct { Id int64 `xml:"id"` TimestampStr string `xml:"timestamp"` Timestamp time.Time `xml:"-"` CancelledQuantity float64 `xml:"cancelledQuantity"` Data []*BrokerExecution `xml:"brokerExecutions>brokerExecution"` } type BrokerExecution struct { Quantity float64 `xml:"quantity"` Price float64 `xml:"price"` } func NewOrderTransactions(eventData string) (*OrderTransactions, error) { r := OrderTransactions{} data := []byte(eventData) err := xml.Unmarshal(data, &r) if err != nil { return nil, err } for i := 0; i < len(r.Data); i++ { r.Data[i].Timestamp = parseTime(r.Data[i].TimestampStr) } return &r, nil }