Skip to content

Instantly share code, notes, and snippets.

@ZhangYet
Created October 28, 2019 11:39
Show Gist options
  • Save ZhangYet/66d570db101fdd01ad8f25d724215925 to your computer and use it in GitHub Desktop.
Save ZhangYet/66d570db101fdd01ad8f25d724215925 to your computer and use it in GitHub Desktop.
package generator
import (
"bytes"
"flag"
"fmt"
"go/format"
"html/template"
"strings"
"github.com/quickfixgo/quickfix"
"github.com/quickfixgo/quickfix/datadictionary"
)
var useFloat = flag.Bool("use-float", true, "By default, FIX float fields are represented as arbitrary-precision fixed-point decimal numbers. Set to 'true' to instead generate FIX float fields as float64 values.")
var CreateMessage = `
func Create{{.Protocol}}{{.MsgName}}Message() *Message {
msg := NewMessage()
{{- range .HeaderFields }}
{{- if (eq .FieldType "FIXString") }}
msg.Header.SetField({{.Tag}}, {{.FieldType}}("{{.FieldValue}}"))
{{- else if (eq .FieldType "FIXUTCTimestamp") }}
msg.Header.SetField({{.Tag}}, FIXUTCTimestamp{time.Now(), true})
{{- else}}
msg.Header.SetField({{.Tag}}, {{.FieldType}}({{.FieldValue}}))
{{- end}}
{{- end}}
{{println}}
{{- range .BodyFields }}
{{- if (eq .FieldType "FIXString") }}
msg.Body.SetField({{.Tag}}, {{.FieldType}}("{{.FieldValue}}"))
{{- else if (eq .FieldType "FIXUTCTimestamp") }}
msg.Body.SetField({{.Tag}}, FIXUTCTimestamp{time.Now(), true})
{{- else}}
msg.Body.SetField({{.Tag}}, {{.FieldType}}({{.FieldValue}}))
{{- end}}
{{- end}}
{{println}}
{{- range .TrailerFields }}
{{- if (eq .FieldType "FIXString") }}
msg.Trailer.SetField({{.Tag}}, {{.FieldType}}("{{.FieldValue}}"))
{{- else if (eq .FieldType "FIXUTCTimestamp") }}
msg.Trailer.SetField({{.Tag}}, FIXUTCTimestamp{time.Now(), true})
{{- else}}
msg.Trailer.SetField({{.Tag}}, {{.FieldType}}({{.FieldValue}}))
{{- end}}
{{- end}}
return msg
}
`
var NewMassageTmpl = template.Must(template.New("NewMessage").Parse(CreateMessage))
type msgField struct {
Tag string
FieldType string
FieldValue string
}
type FixMsgTmplStruct struct {
Protocol string
MsgName string
HeaderFields []msgField
BodyFields []msgField
TrailerFields []msgField
}
func GenCode(msg *quickfix.Message, dict *datadictionary.DataDictionary) (string, error) {
msgName, err := msg.MsgType()
if err != nil {
return "", err
}
protocal, err := msg.Header.GetString(quickfix.Tag(8))
if err != nil {
return "", err
}
fixMsg := FixMsgTmplStruct{
Protocol: strings.Replace(protocal, ".", "", -1),
MsgName: string(msgName),
HeaderFields: make([]msgField, 0),
BodyFields: make([]msgField, 0),
TrailerFields: make([]msgField, 0),
}
for _, tag := range msg.Header.Tags() {
mf, err := genMsgField(tag, msg.Header.FieldMap, dict)
if err != nil {
return "", err
}
fixMsg.HeaderFields = append(fixMsg.HeaderFields, mf)
}
for _, tag := range msg.Body.Tags() {
mf, err := genMsgField(tag, msg.Body.FieldMap, dict)
if err != nil {
return "", err
}
fixMsg.BodyFields = append(fixMsg.BodyFields, mf)
}
for _, tag := range msg.Trailer.Tags() {
mf, err := genMsgField(tag, msg.Trailer.FieldMap, dict)
if err != nil {
return "", err
}
fixMsg.TrailerFields = append(fixMsg.TrailerFields, mf)
}
code, genCodeErr := genCode(fixMsg)
if genCodeErr != nil {
return "", genCodeErr
}
formattedCodeByte, formatErr := format.Source([]byte(code))
if formatErr != nil {
fmt.Printf("format error: %v\n", formatErr)
return code, nil
}
return string(formattedCodeByte), nil
}
func genCode(data FixMsgTmplStruct) (string, error) {
buffer := new(bytes.Buffer)
if err := NewMassageTmpl.Execute(buffer, data); err != nil {
return "", err
}
return buffer.String(), nil
}
func genMsgField(tag quickfix.Tag, fieldMap quickfix.FieldMap, dict *datadictionary.DataDictionary) (msgField, error) {
mf := msgField{
Tag: "",
}
tagStr := fmt.Sprintf("Tag(%d)", tag)
fieldType, ok := dict.FieldTypeByTag[int(tag)]
if !ok {
return mf, fmt.Errorf("%d didn't exists", tag)
}
fieldTypeStr, err := quickfixType(fieldType)
if err != nil {
return mf, err
}
value, err := fieldMap.GetString(tag)
if err != nil {
return mf, err
}
mf = msgField{
Tag: tagStr,
FieldType: fieldTypeStr,
FieldValue: value,
}
return mf, nil
}
func quickfixType(field *datadictionary.FieldType) (quickfixType string, err error) {
switch field.Type {
case "MULTIPLESTRINGVALUE", "MULTIPLEVALUESTRING":
fallthrough
case "MULTIPLECHARVALUE":
fallthrough
case "CHAR":
fallthrough
case "CURRENCY":
fallthrough
case "DATA":
fallthrough
case "MONTHYEAR":
fallthrough
case "LOCALMKTDATE":
fallthrough
case "TIME":
fallthrough
case "DATE":
fallthrough
case "EXCHANGE":
fallthrough
case "LANGUAGE":
fallthrough
case "XMLDATA":
fallthrough
case "COUNTRY":
fallthrough
case "UTCTIMEONLY":
fallthrough
case "UTCDATE":
fallthrough
case "UTCDATEONLY":
fallthrough
case "TZTIMEONLY":
fallthrough
case "TZTIMESTAMP":
fallthrough
case "STRING":
quickfixType = "FIXString"
case "BOOLEAN":
quickfixType = "FIXBoolean"
case "LENGTH":
fallthrough
case "DAYOFMONTH":
fallthrough
case "NUMINGROUP":
fallthrough
case "SEQNUM":
fallthrough
case "INT":
quickfixType = "FIXInt"
case "UTCTIMESTAMP":
quickfixType = "FIXUTCTimestamp"
case "QTY":
fallthrough
case "QUANTITY":
fallthrough
case "AMT":
fallthrough
case "PRICE":
fallthrough
case "PRICEOFFSET":
fallthrough
case "PERCENTAGE":
fallthrough
case "FLOAT":
if *useFloat {
quickfixType = "FIXFloat"
} else {
quickfixType = "FIXDecimal"
}
default:
err = fmt.Errorf("Unknown type '%v' for tag '%v'\n", field.Type, field.Tag())
}
return
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment