mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-26 00:35:15 +00:00
refactor server routes
This commit is contained in:
parent
d5b1472560
commit
c1b2114dd2
|
@ -5,6 +5,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
@ -44,16 +45,12 @@ type Server struct {
|
||||||
Environ *bbgo.Environment
|
Environ *bbgo.Environment
|
||||||
Trader *bbgo.Trader
|
Trader *bbgo.Trader
|
||||||
Setup *Setup
|
Setup *Setup
|
||||||
Bind string
|
|
||||||
OpenInBrowser bool
|
OpenInBrowser bool
|
||||||
|
|
||||||
srv *http.Server
|
srv *http.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) Run(ctx context.Context) error {
|
func (s *Server) newEngine() *gin.Engine {
|
||||||
userConfig := s.Config
|
|
||||||
environ := s.Environ
|
|
||||||
|
|
||||||
r := gin.Default()
|
r := gin.Default()
|
||||||
r.Use(cors.New(cors.Config{
|
r.Use(cors.New(cors.Config{
|
||||||
AllowOrigins: []string{"*"},
|
AllowOrigins: []string{"*"},
|
||||||
|
@ -76,7 +73,7 @@ func (s *Server) Run(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
r.GET("/api/trades", func(c *gin.Context) {
|
r.GET("/api/trades", func(c *gin.Context) {
|
||||||
if environ.TradeService == nil {
|
if s.Environ.TradeService == nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "database is not configured"})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "database is not configured"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -91,7 +88,7 @@ func (s *Server) Run(ctx context.Context) error {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
trades, err := environ.TradeService.Query(service.QueryTradesOptions{
|
trades, err := s.Environ.TradeService.Query(service.QueryTradesOptions{
|
||||||
Exchange: types.ExchangeName(exchange),
|
Exchange: types.ExchangeName(exchange),
|
||||||
Symbol: symbol,
|
Symbol: symbol,
|
||||||
LastGID: lastGID,
|
LastGID: lastGID,
|
||||||
|
@ -108,91 +105,8 @@ func (s *Server) Run(ctx context.Context) error {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
r.GET("/api/orders/closed", func(c *gin.Context) {
|
r.GET("/api/orders/closed", s.listClosedOrders)
|
||||||
if environ.OrderService == nil {
|
r.GET("/api/trading-volume", s.tradingVolume)
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "database is not configured"})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
exchange := c.Query("exchange")
|
|
||||||
symbol := c.Query("symbol")
|
|
||||||
gidStr := c.DefaultQuery("gid", "0")
|
|
||||||
|
|
||||||
lastGID, err := strconv.ParseInt(gidStr, 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
logrus.WithError(err).Error("last gid parse error")
|
|
||||||
c.Status(http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
orders, err := environ.OrderService.Query(service.QueryOrdersOptions{
|
|
||||||
Exchange: types.ExchangeName(exchange),
|
|
||||||
Symbol: symbol,
|
|
||||||
LastGID: lastGID,
|
|
||||||
Ordering: "DESC",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
c.Status(http.StatusBadRequest)
|
|
||||||
logrus.WithError(err).Error("order query error")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
|
||||||
"orders": orders,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
r.GET("/api/trading-volume", func(c *gin.Context) {
|
|
||||||
if environ.TradeService == nil {
|
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "database is not configured"})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
period := c.DefaultQuery("period", "day")
|
|
||||||
segment := c.DefaultQuery("segment", "exchange")
|
|
||||||
startTimeStr := c.Query("start-time")
|
|
||||||
|
|
||||||
var startTime time.Time
|
|
||||||
|
|
||||||
if startTimeStr != "" {
|
|
||||||
v, err := time.Parse(time.RFC3339, startTimeStr)
|
|
||||||
if err != nil {
|
|
||||||
c.Status(http.StatusBadRequest)
|
|
||||||
logrus.WithError(err).Error("start-time format incorrect")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
startTime = v
|
|
||||||
|
|
||||||
} else {
|
|
||||||
switch period {
|
|
||||||
case "day":
|
|
||||||
startTime = time.Now().AddDate(0, 0, -30)
|
|
||||||
|
|
||||||
case "month":
|
|
||||||
startTime = time.Now().AddDate(0, -6, 0)
|
|
||||||
|
|
||||||
case "year":
|
|
||||||
startTime = time.Now().AddDate(-2, 0, 0)
|
|
||||||
|
|
||||||
default:
|
|
||||||
startTime = time.Now().AddDate(0, 0, -7)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rows, err := environ.TradeService.QueryTradingVolume(startTime, service.TradingVolumeQueryOptions{
|
|
||||||
SegmentBy: segment,
|
|
||||||
GroupByPeriod: period,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
logrus.WithError(err).Error("trading volume query error")
|
|
||||||
c.Status(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{"tradingVolumes": rows})
|
|
||||||
return
|
|
||||||
})
|
|
||||||
|
|
||||||
r.POST("/api/sessions/test", func(c *gin.Context) {
|
r.POST("/api/sessions/test", func(c *gin.Context) {
|
||||||
var sessionConfig bbgo.ExchangeSession
|
var sessionConfig bbgo.ExchangeSession
|
||||||
|
@ -212,12 +126,12 @@ func (s *Server) Run(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
var anyErr error
|
var anyErr error
|
||||||
_, openOrdersErr := session.Exchange.QueryOpenOrders(ctx, "BTCUSDT")
|
_, openOrdersErr := session.Exchange.QueryOpenOrders(c, "BTCUSDT")
|
||||||
if openOrdersErr != nil {
|
if openOrdersErr != nil {
|
||||||
anyErr = openOrdersErr
|
anyErr = openOrdersErr
|
||||||
}
|
}
|
||||||
|
|
||||||
_, balanceErr := session.Exchange.QueryAccountBalances(ctx)
|
_, balanceErr := session.Exchange.QueryAccountBalances(c)
|
||||||
if balanceErr != nil {
|
if balanceErr != nil {
|
||||||
anyErr = balanceErr
|
anyErr = balanceErr
|
||||||
}
|
}
|
||||||
|
@ -232,7 +146,7 @@ func (s *Server) Run(ctx context.Context) error {
|
||||||
|
|
||||||
r.GET("/api/sessions", func(c *gin.Context) {
|
r.GET("/api/sessions", func(c *gin.Context) {
|
||||||
var sessions []*bbgo.ExchangeSession
|
var sessions []*bbgo.ExchangeSession
|
||||||
for _, session := range environ.Sessions() {
|
for _, session := range s.Environ.Sessions() {
|
||||||
sessions = append(sessions, session)
|
sessions = append(sessions, session)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,120 +174,33 @@ func (s *Server) Run(ctx context.Context) error {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if userConfig.Sessions == nil {
|
if s.Config.Sessions == nil {
|
||||||
userConfig.Sessions = make(map[string]*bbgo.ExchangeSession)
|
s.Config.Sessions = make(map[string]*bbgo.ExchangeSession)
|
||||||
}
|
}
|
||||||
userConfig.Sessions[sessionConfig.Name] = session
|
s.Config.Sessions[sessionConfig.Name] = session
|
||||||
|
|
||||||
environ.AddExchangeSession(sessionConfig.Name, session)
|
s.Environ.AddExchangeSession(sessionConfig.Name, session)
|
||||||
|
|
||||||
if err := session.Init(ctx, environ); err != nil {
|
if err := session.Init(c, s.Environ); err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{
|
c.JSON(http.StatusInternalServerError, gin.H{
|
||||||
"error": err.Error(),
|
"error": err.Error(),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{"success": true})
|
||||||
"success": true,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
r.GET("/api/assets", func(c *gin.Context) {
|
r.GET("/api/assets", s.listAssets)
|
||||||
totalAssets := types.AssetMap{}
|
r.GET("/api/sessions/:session", s.listSessions)
|
||||||
|
r.GET("/api/sessions/:session/trades", s.listSessionTrades)
|
||||||
for _, session := range environ.Sessions() {
|
r.GET("/api/sessions/:session/open-orders", s.listSessionOpenOrders)
|
||||||
balances := session.Account.Balances()
|
r.GET("/api/sessions/:session/account", s.getSessionAccount)
|
||||||
|
r.GET("/api/sessions/:session/account/balances", s.getSessionAccountBalance)
|
||||||
if err := session.UpdatePrices(ctx); err != nil {
|
|
||||||
logrus.WithError(err).Error("price update failed")
|
|
||||||
c.Status(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
assets := balances.Assets(session.LastPrices())
|
|
||||||
|
|
||||||
for currency, asset := range assets {
|
|
||||||
totalAssets[currency] = asset
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{"assets": totalAssets})
|
|
||||||
})
|
|
||||||
|
|
||||||
r.GET("/api/sessions/:session", func(c *gin.Context) {
|
|
||||||
sessionName := c.Param("session")
|
|
||||||
session, ok := environ.Session(sessionName)
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("session %s not found", sessionName)})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{"session": session})
|
|
||||||
})
|
|
||||||
|
|
||||||
r.GET("/api/sessions/:session/trades", func(c *gin.Context) {
|
|
||||||
sessionName := c.Param("session")
|
|
||||||
session, ok := environ.Session(sessionName)
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("session %s not found", sessionName)})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{"trades": session.Trades})
|
|
||||||
})
|
|
||||||
|
|
||||||
r.GET("/api/sessions/:session/open-orders", func(c *gin.Context) {
|
|
||||||
sessionName := c.Param("session")
|
|
||||||
session, ok := environ.Session(sessionName)
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("session %s not found", sessionName)})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
marketOrders := make(map[string][]types.Order)
|
|
||||||
for symbol, orderStore := range session.OrderStores() {
|
|
||||||
marketOrders[symbol] = orderStore.Orders()
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{"orders": marketOrders})
|
|
||||||
})
|
|
||||||
|
|
||||||
r.GET("/api/sessions/:session/account", func(c *gin.Context) {
|
|
||||||
sessionName := c.Param("session")
|
|
||||||
session, ok := environ.Session(sessionName)
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("session %s not found", sessionName)})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{"account": session.Account})
|
|
||||||
})
|
|
||||||
|
|
||||||
r.GET("/api/sessions/:session/account/balances", func(c *gin.Context) {
|
|
||||||
sessionName := c.Param("session")
|
|
||||||
session, ok := environ.Session(sessionName)
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("session %s not found", sessionName)})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if session.Account == nil {
|
|
||||||
c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("the account of session %s is nil", sessionName)})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{"balances": session.Account.Balances()})
|
|
||||||
})
|
|
||||||
|
|
||||||
r.GET("/api/sessions/:session/symbols", func(c *gin.Context) {
|
r.GET("/api/sessions/:session/symbols", func(c *gin.Context) {
|
||||||
sessionName := c.Param("session")
|
sessionName := c.Param("session")
|
||||||
session, ok := environ.Session(sessionName)
|
session, ok := s.Environ.Session(sessionName)
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("session %s not found", sessionName)})
|
c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("session %s not found", sessionName)})
|
||||||
|
@ -407,29 +234,67 @@ func (s *Server) Run(ctx context.Context) error {
|
||||||
r.GET("/api/strategies/single", s.listStrategies)
|
r.GET("/api/strategies/single", s.listStrategies)
|
||||||
r.NoRoute(s.pkgerHandler)
|
r.NoRoute(s.pkgerHandler)
|
||||||
|
|
||||||
if s.OpenInBrowser {
|
return r
|
||||||
if runtime.GOOS == "darwin" {
|
|
||||||
baseURL := "http://" + DefaultBindAddress
|
|
||||||
if len(s.Bind) > 0 {
|
|
||||||
baseURL = "http://" + s.Bind
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) Run(ctx context.Context, bindArgs ...string) error {
|
||||||
|
r := s.newEngine()
|
||||||
|
bind := resolveBind(bindArgs)
|
||||||
|
if s.OpenInBrowser {
|
||||||
|
s.openBrowser(ctx, bind)
|
||||||
|
}
|
||||||
|
|
||||||
|
s.srv = newServer(r, bind)
|
||||||
|
return listenAndServe(s.srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) openBrowser(ctx context.Context, bind string) {
|
||||||
|
if runtime.GOOS == "darwin" {
|
||||||
|
baseURL := "http://" + bind
|
||||||
go pingAndOpenURL(ctx, baseURL)
|
go pingAndOpenURL(ctx, baseURL)
|
||||||
} else {
|
} else {
|
||||||
logrus.Warnf("%s is not supported for opening browser automatically", runtime.GOOS)
|
logrus.Warnf("%s is not supported for opening browser automatically", runtime.GOOS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bind := DefaultBindAddress
|
func resolveBind(a []string) string {
|
||||||
if len(s.Bind) > 0 {
|
switch len(a) {
|
||||||
bind = s.Bind
|
case 0:
|
||||||
|
return DefaultBindAddress
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
return a[0]
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic("too many parameters for binding")
|
||||||
}
|
}
|
||||||
|
|
||||||
s.srv = &http.Server{
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func newServer(r http.Handler, bind string) *http.Server {
|
||||||
|
return &http.Server{
|
||||||
Addr: bind,
|
Addr: bind,
|
||||||
Handler: r,
|
Handler: r,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func serve(srv *http.Server, l net.Listener) (err error) {
|
||||||
|
defer func() {
|
||||||
|
if err != nil && err != http.ErrServerClosed {
|
||||||
|
logrus.WithError(err).Error("unexpected http server error")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = srv.Serve(l)
|
||||||
|
if err != http.ErrServerClosed {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func listenAndServe(srv *http.Server) error {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
|
@ -438,7 +303,7 @@ func (s *Server) Run(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
err = s.srv.ListenAndServe()
|
err = srv.ListenAndServe()
|
||||||
if err != http.ErrServerClosed {
|
if err != http.ErrServerClosed {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -576,6 +441,40 @@ func (s *Server) setupRestart(c *gin.Context) {
|
||||||
c.JSON(http.StatusOK, gin.H{"success": true})
|
c.JSON(http.StatusOK, gin.H{"success": true})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) listClosedOrders(c *gin.Context) {
|
||||||
|
if s.Environ.OrderService == nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "database is not configured"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
exchange := c.Query("exchange")
|
||||||
|
symbol := c.Query("symbol")
|
||||||
|
gidStr := c.DefaultQuery("gid", "0")
|
||||||
|
|
||||||
|
lastGID, err := strconv.ParseInt(gidStr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Error("last gid parse error")
|
||||||
|
c.Status(http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
orders, err := s.Environ.OrderService.Query(service.QueryOrdersOptions{
|
||||||
|
Exchange: types.ExchangeName(exchange),
|
||||||
|
Symbol: symbol,
|
||||||
|
LastGID: lastGID,
|
||||||
|
Ordering: "DESC",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
c.Status(http.StatusBadRequest)
|
||||||
|
logrus.WithError(err).Error("order query error")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"orders": orders,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) listStrategies(c *gin.Context) {
|
func (s *Server) listStrategies(c *gin.Context) {
|
||||||
var stashes []map[string]interface{}
|
var stashes []map[string]interface{}
|
||||||
|
|
||||||
|
@ -597,23 +496,113 @@ func (s *Server) listStrategies(c *gin.Context) {
|
||||||
c.JSON(http.StatusOK, gin.H{"strategies": stashes})
|
c.JSON(http.StatusOK, gin.H{"strategies": stashes})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) setupSaveConfig(c *gin.Context) {
|
func (s *Server) listSessions(c *gin.Context) {
|
||||||
userConfig := s.Config
|
sessionName := c.Param("session")
|
||||||
environ := s.Environ
|
session, ok := s.Environ.Session(sessionName)
|
||||||
|
|
||||||
if len(userConfig.Sessions) == 0 {
|
if !ok {
|
||||||
|
c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("session %s not found", sessionName)})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{"session": session})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) listSessionTrades(c *gin.Context) {
|
||||||
|
sessionName := c.Param("session")
|
||||||
|
session, ok := s.Environ.Session(sessionName)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("session %s not found", sessionName)})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{"trades": session.Trades})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) getSessionAccount(c *gin.Context) {
|
||||||
|
sessionName := c.Param("session")
|
||||||
|
session, ok := s.Environ.Session(sessionName)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("session %s not found", sessionName)})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{"account": session.Account})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) getSessionAccountBalance(c *gin.Context) {
|
||||||
|
sessionName := c.Param("session")
|
||||||
|
session, ok := s.Environ.Session(sessionName)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("session %s not found", sessionName)})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if session.Account == nil {
|
||||||
|
c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("the account of session %s is nil", sessionName)})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{"balances": session.Account.Balances()})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) listSessionOpenOrders(c *gin.Context) {
|
||||||
|
sessionName := c.Param("session")
|
||||||
|
session, ok := s.Environ.Session(sessionName)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
c.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("session %s not found", sessionName)})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
marketOrders := make(map[string][]types.Order)
|
||||||
|
for symbol, orderStore := range session.OrderStores() {
|
||||||
|
marketOrders[symbol] = orderStore.Orders()
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{"orders": marketOrders})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) listAssets(c *gin.Context) {
|
||||||
|
totalAssets := types.AssetMap{}
|
||||||
|
|
||||||
|
for _, session := range s.Environ.Sessions() {
|
||||||
|
balances := session.Account.Balances()
|
||||||
|
|
||||||
|
if err := session.UpdatePrices(c); err != nil {
|
||||||
|
logrus.WithError(err).Error("price update failed")
|
||||||
|
c.Status(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
assets := balances.Assets(session.LastPrices())
|
||||||
|
|
||||||
|
for currency, asset := range assets {
|
||||||
|
totalAssets[currency] = asset
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{"assets": totalAssets})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) setupSaveConfig(c *gin.Context) {
|
||||||
|
if len(s.Config.Sessions) == 0 {
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"error": "session is not configured"})
|
c.JSON(http.StatusBadRequest, gin.H{"error": "session is not configured"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
envVars, err := collectSessionEnvVars(userConfig.Sessions)
|
envVars, err := collectSessionEnvVars(s.Config.Sessions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(s.Environ.MysqlURL) > 0 {
|
if len(s.Environ.MysqlURL) > 0 {
|
||||||
envVars["MYSQL_URL"] = environ.MysqlURL
|
envVars["MYSQL_URL"] = s.Environ.MysqlURL
|
||||||
}
|
}
|
||||||
|
|
||||||
dotenvFile := ".env.local"
|
dotenvFile := ".env.local"
|
||||||
|
@ -627,7 +616,7 @@ func (s *Server) setupSaveConfig(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
out, err := userConfig.YAML()
|
out, err := s.Config.YAML()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
|
@ -711,6 +700,58 @@ func collectSessionEnvVars(sessions map[string]*bbgo.ExchangeSession) (envVars m
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) tradingVolume(c *gin.Context) {
|
||||||
|
if s.Environ.TradeService == nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "database is not configured"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
period := c.DefaultQuery("period", "day")
|
||||||
|
segment := c.DefaultQuery("segment", "exchange")
|
||||||
|
startTimeStr := c.Query("start-time")
|
||||||
|
|
||||||
|
var startTime time.Time
|
||||||
|
|
||||||
|
if startTimeStr != "" {
|
||||||
|
v, err := time.Parse(time.RFC3339, startTimeStr)
|
||||||
|
if err != nil {
|
||||||
|
c.Status(http.StatusBadRequest)
|
||||||
|
logrus.WithError(err).Error("start-time format incorrect")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
startTime = v
|
||||||
|
|
||||||
|
} else {
|
||||||
|
switch period {
|
||||||
|
case "day":
|
||||||
|
startTime = time.Now().AddDate(0, 0, -30)
|
||||||
|
|
||||||
|
case "month":
|
||||||
|
startTime = time.Now().AddDate(0, -6, 0)
|
||||||
|
|
||||||
|
case "year":
|
||||||
|
startTime = time.Now().AddDate(-2, 0, 0)
|
||||||
|
|
||||||
|
default:
|
||||||
|
startTime = time.Now().AddDate(0, 0, -7)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rows, err := s.Environ.TradeService.QueryTradingVolume(startTime, service.TradingVolumeQueryOptions{
|
||||||
|
SegmentBy: segment,
|
||||||
|
GroupByPeriod: period,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Error("trading volume query error")
|
||||||
|
c.Status(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{"tradingVolumes": rows})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func getJSON(url string, data interface{}) error {
|
func getJSON(url string, data interface{}) error {
|
||||||
var client = &http.Client{Timeout: 500 * time.Millisecond}
|
var client = &http.Client{Timeout: 500 * time.Millisecond}
|
||||||
r, err := client.Get(url)
|
r, err := client.Get(url)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user