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
}