Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
f0cii committed May 15, 2020
1 parent e45b839 commit a49a4df
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 86 deletions.
35 changes: 19 additions & 16 deletions backtest/ReportHistoryTemplate.html
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
<td nowrap><b><!--Buy & Hold Return [%]--></b></td>
</tr>
<tr>
<td nowrap style="width: 140px;height: 10px"></td>
<td nowrap style="width: 120px;height: 10px"></td>
<td nowrap style="width: 60px;"></td>
<td nowrap style="width: 60px;"></td>
<td nowrap style="width: 60px;"></td>
Expand All @@ -91,8 +91,8 @@
<td nowrap style="width: 70px;"></td>
<td nowrap style="width: 70px;"></td>
<td nowrap style="width: 70px;"></td>
<td nowrap style="width: 70px;"></td>
<td nowrap style="width: 60px;"></td>
<td nowrap style="width: 120px;"></td>
<td nowrap style="width: 40px;"></td>
<td nowrap style="width: 100px;"></td>
</tr>
<tr align="center">
Expand All @@ -103,36 +103,39 @@
<td nowrap><b>Order</b></td>
<td nowrap><b>Symbol</b></td>
<td nowrap><b>Type</b></td>
<td nowrap colspan="2"><b>Volume</b></td>
<td nowrap><b>Amount</b></td>
<td nowrap><b>Price</b></td>
<td nowrap><b>Avg Price</b></td>
<td nowrap><b>SL/TP</b></td>
<td nowrap colspan="2"><b>Time</b></td>
<td nowrap><b>Profit</b></td>
<td nowrap><b>Commission</b></td>
<td nowrap><b>Balance</b></td>
<td nowrap><b>Time</b></td>
<td nowrap><b>State</b></td>
<td nowrap><b>Comment</b></td>
<td nowrap><b>Position</b></td>
</tr>
<!--{order-row}-->
<!--{order-rows}-->
<tr>
<td nowrap style="height: 10px"></td>
</tr>
<tr align="center">
<th colspan="13" style="height: 25px"><div style="font: 10pt Tahoma"><b>Deals</b></div></th>
</tr>
<tr align="center" bgcolor="#E5F0FC">
<td nowrap style="height: 30px"><b>Time</b></td>
<td nowrap><b>Deal</b></td>
<td nowrap style="height: 30px"><b>Open Time</b></td>
<td nowrap><b>Order</b></td>
<td nowrap><b>Symbol</b></td>
<td nowrap><b>Type</b></td>
<td nowrap><b>Direction</b></td>
<td nowrap><b>Volume</b></td>
<td nowrap><b>Amount</b></td>
<td nowrap><b>Price</b></td>
<td nowrap><b>Order</b></td>
<td nowrap><b>Commission</b></td>
<td nowrap><b>Swap</b></td>
<td nowrap><b>Avg Price</b></td>
<td nowrap><b>Profit</b></td>
<td nowrap><b>Commission</b></td>
<td nowrap><b>Balance</b></td>
<td nowrap><b>Comment</b></td>
<td nowrap><b>Time</b></td>
<td nowrap><b>State</b></td>
<td nowrap><b>Position</b></td>
</tr>
<!--{deal-order-rows}-->
<!--
<tr bgcolor="#FFFFFF" align="right"><td nowrap>2018.06.01 03:08:53</td><td nowrap>10320598</td><td nowrap></td><td nowrap>balance</td><td nowrap></td><td nowrap></td><td nowrap></td><td nowrap></td><td nowrap>0.00</td><td nowrap>0.00</td><td nowrap>50 000.00</td><td nowrap>50 000.00</td><td nowrap></td></tr>
<tr bgcolor="#F7F7F7" align="right"><td nowrap>2018.12.03 09:45:34</td><td nowrap>10890657</td><td nowrap>USDCHF</td><td nowrap>sell</td><td nowrap>in</td><td nowrap>0.20</td><td nowrap>0.99669</td><td nowrap>11984150</td><td nowrap>0.00</td><td nowrap>0.00</td><td nowrap>0.00</td><td nowrap>50 000.00</td><td nowrap></td></tr>
Expand Down
83 changes: 62 additions & 21 deletions backtest/backtest.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
slog "log"
"os"
"path/filepath"
"sort"
"strings"
"time"
)
Expand Down Expand Up @@ -293,25 +294,25 @@ func (b *Backtest) htmlReport(path string) (err error) {
htmlPath := filepath.Join(dir, name+".html")
//slog.Printf("htmlPath: %v", htmlPath)

var orders []*SOrder
var sOrders []*SOrder
var dealOrders []*SOrder
orders, dealOrders, err = b.readTradeLog(path)
sOrders, dealOrders, err = b.readTradeLog(path)
if err != nil {
return
}

//for _, v := range orders {
// slog.Printf("orders Ts: %v Order: %v OrderBook: %v Comment: %v",
//for _, v := range sOrders {
// slog.Printf("sOrders Ts: %v Order: %v OrderBook: %v Comment: %v",
// v.Ts, v.Order, v.OrderBook, v.Comment)
//}

var html string
html, err = b.buildReportHtml(orders, dealOrders)
html, err = b.buildReportHtml(sOrders, dealOrders)
err = ioutil.WriteFile(htmlPath, []byte(html), os.ModePerm)
return
}

func (b *Backtest) buildReportHtml(orders []*SOrder, dealOrders []*SOrder) (html string, err error) {
func (b *Backtest) buildReportHtml(sOrders []*SOrder, dealOrders []*SOrder) (html string, err error) {
//var templateData []byte
//templateData, err = ioutil.ReadFile("./ReportHistory-template.html")
//if err != nil {
Expand All @@ -335,35 +336,66 @@ func (b *Backtest) buildReportHtml(orders []*SOrder, dealOrders []*SOrder) (html
html = strings.ReplaceAll(html, "<!--Run Duration-->", stats.RunDuration.String())
html = strings.ReplaceAll(html, "<!--Buy & Hold Return-->", fmt.Sprintf("%.8f", stats.BaHReturn))
html = strings.ReplaceAll(html, "<!--Buy & Hold Return [%]-->", fmt.Sprintf("%.4f", stats.BaHReturnPnt*100))
s := b.buildSOrders(sOrders)
html = strings.Replace(html, `<!--{order-rows}-->`, s, -1)
s = b.buildSOrders(dealOrders)
html = strings.Replace(html, `<!--{deal-order-rows}-->`, s, -1)
return
}

func (b *Backtest) buildSOrders(sOrders []*SOrder) string {
s := bytes.Buffer{}
for i := 0; i < len(orders); i++ {
order := orders[i].Order
for i := 0; i < len(sOrders); i++ {
sOrder := sOrders[i]
order := sOrders[i].Order
bgColor := "#FFFFFF"
if i%2 != 0 {
bgColor = "#F7F7F7"
}
s.WriteString(fmt.Sprintf(`<tr bgcolor="%v" align="right">`, bgColor)) // #FFFFFF
s.WriteString(fmt.Sprintf(`<td>%v</td>`, order.Time.Format("2006.01.02 15:04:05"))) // 2018.07.06 11:08:44
s.WriteString(fmt.Sprintf(`<td>%v</td>`, order.ID)) // 11573668
price := fmt.Sprintf("%v", order.Price)
orderType := strings.ToLower(order.Direction.String())
if order.Type == OrderTypeMarket {
price = "market"
} else {
orderType += " " + strings.ToLower(order.Type.String())
}
if order.PostOnly {
orderType += " postOnly"
}
if order.ReduceOnly {
orderType += " reduceOnly"
}
positions := ""
sort.Slice(sOrder.Positions, func(i, j int) bool {
return sOrder.Positions[i].Size > sOrder.Positions[j].Size
})
for _, v := range sOrder.Positions {
if positions != "" {
positions += " / "
}
positions += fmt.Sprintf("%v", v.Size)
}
s.WriteString(fmt.Sprintf(`<tr bgcolor="%v" align="right">`, bgColor)) // #FFFFFF
s.WriteString(fmt.Sprintf(`<td>%v</td>`, order.Time.Format("2006.01.02 15:04:05.000"))) // 2018.07.06 11:08:44
s.WriteString(fmt.Sprintf(`<td>%v</td>`, order.ID)) // 11573668
s.WriteString(fmt.Sprintf(`<td>%v</td>`, order.Symbol))
s.WriteString(fmt.Sprintf(`<td>%v %v</td>`,
strings.ToLower(order.Direction.String()),
strings.ToLower(order.Type.String()))) // buy limit
s.WriteString(fmt.Sprintf(`<td colspan="2">%v / %v</td>`, order.Amount, order.FilledAmount)) // 0.20 / 0.00
s.WriteString(fmt.Sprintf(`<td>%v</td>`, order.Price)) // 1.16673
s.WriteString(fmt.Sprintf(`<td>%v</td>`, orderType)) // buy limit/buy
s.WriteString(fmt.Sprintf(`<td>%v / %v</td>`, order.Amount, order.FilledAmount)) // 0.20 / 0.00
s.WriteString(fmt.Sprintf(`<td>%v</td>`, price)) // 1.16673
if order.AvgPrice > 0 {
s.WriteString(fmt.Sprintf(`<td>%v</td>`, order.AvgPrice))
} else {
s.WriteString(`<td></td>`)
}
s.WriteString(`<td></td>`)
s.WriteString(fmt.Sprintf(`<td colspan="2">%v</td>`, order.UpdateTime.Format("2006.01.02 15:04:05")))
s.WriteString(fmt.Sprintf(`<td>%.8f</td>`, order.Pnl))
s.WriteString(fmt.Sprintf(`<td>%.8f</td>`, order.Commission))
s.WriteString(fmt.Sprintf(`<td>%v</td>`, sOrder.Balance))
s.WriteString(fmt.Sprintf(`<td>%v</td>`, order.UpdateTime.Format("2006.01.02 15:04:05.000")))
s.WriteString(fmt.Sprintf(`<td>%v</td>`, order.Status.String())) // canceled
s.WriteString(`<td></td>`)
s.WriteString(fmt.Sprintf(`<td>%v</td>`, positions))
s.WriteString(`</tr>`)
}
html = strings.Replace(html, `<!--{order-row}-->`, s.String(), -1)
return
return s.String()
}

func (b *Backtest) readTradeLog(path string) (orders []*SOrder, dealOrders []*SOrder, err error) {
Expand Down Expand Up @@ -400,12 +432,15 @@ func (b *Backtest) parseSOrder(s string) (event string, so *SOrder, err error) {
if eventValue := ret.Get("event"); eventValue.Exists() {
var order Order
var orderbook OrderBook
var positions []*Position

event = eventValue.String()
tsString := ret.Get("ts").String() // 2019-10-01T08:00:00.143+0800
msg := ret.Get("msg").String()
orderJson := ret.Get("order").String()
orderbookJson := ret.Get("orderbook").String()
positionsJson := ret.Get("positions").String()
balance := ret.Get("balance").Float()

err = json.Unmarshal([]byte(orderJson), &order)
if err != nil {
Expand All @@ -415,6 +450,10 @@ func (b *Backtest) parseSOrder(s string) (event string, so *SOrder, err error) {
if err != nil {
return
}
err = json.Unmarshal([]byte(positionsJson), &positions)
if err != nil {
return
}
var ts time.Time
ts, err = time.Parse("2006-01-02T15:04:05.000Z0700", tsString)
if err != nil {
Expand All @@ -424,6 +463,8 @@ func (b *Backtest) parseSOrder(s string) (event string, so *SOrder, err error) {
Ts: ts,
Order: &order,
OrderBook: &orderbook,
Positions: positions,
Balance: balance,
Comment: msg,
}
}
Expand Down
10 changes: 6 additions & 4 deletions backtest/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import (

// SOrder "event":"order"/"deal"
type SOrder struct {
Ts time.Time // ts: 2019-10-02T07:03:53.584+0800
Order *Order // order
OrderBook *OrderBook // orderbook
Comment string // msg: Place order/Match order
Ts time.Time // ts: 2019-10-02T07:03:53.584+0800
Order *Order // order
OrderBook *OrderBook // orderbook
Positions []*Position // positions
Balance float64 // balance
Comment string // msg: Place order/Match order
}
2 changes: 1 addition & 1 deletion backtest/statik/statik.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit a49a4df

Please sign in to comment.