Browse Source

backtest

main
strange 10 months ago
parent
commit
d323fe721c
  1. 4
      config/exchange.toml
  2. 2
      internal/trading/backtest/account.go
  3. 17
      internal/trading/backtest/types.go
  4. 4
      internal/trading/okx/account_holder.go
  5. 14
      pkg/trade/account.go
  6. 2
      pkg/trade/error.go
  7. 9
      pkg/trade/risk_strategy.go
  8. 34
      pkg/trader/indicator.go
  9. 42
      pkg/trader/strategy.go
  10. 78
      pkg/trader/strategy_trend_trace.go
  11. 66
      pkg/trader/trader_meta.go

4
config/exchange.toml

@ -18,8 +18,8 @@ receiveBuffer = 4096
marketSubscribeLimit = 16
consumeBatch = 1024
consumeLater = 2000 # 时间到达later或者数据累计到batch触发consume
# httpProxy = "http://192.168.1.5:7890"
httpProxy = "http://10.255.183.209:7890"
httpProxy = "http://192.168.1.5:7890"
# httpProxy = "http://10.255.183.209:7890"
# 模拟盘API交易地址如下:
# REST:https://www.okx.com

2
internal/trading/backtest/account.go

@ -124,7 +124,7 @@ func (a *Account) ClosePosition(index int, kline types.Kline, ts int64, cause st
}
t = a.Simulator.ExecuteMarket(closeSide, pos.Qty, kline, ts)
t.Cause = cause
t.CloseCause = cause
// apply cash change
if closeSide == pb.Side_SELL {
// selling a long position -> receive cash

17
internal/trading/backtest/types.go

@ -15,12 +15,17 @@ type Position struct {
}
type Trade struct {
Side Side
Qty float64
Price float64
Fee float64
Ts int64
Cause string // close reason or 'open' for open trades, ["stoploss", "takeprofit", "trailing", "retrace", "signal"](“止损”、“止盈”、“动态跟踪”、“回撤”、“信号”)
Id int64 // 交易id
Side pb.Side // 交易方向
Status int32 // 1.交易中 2.持仓中 3.已平仓
Qty float64 // 交易量
Price float64 // 开仓价格
Fee float64 // 开仓手续费
Ts int64 // 开仓时间
ClosePrice float64 // 平仓价格
CloseFee float64 // 平仓手续费
CloseTs int64 // 平仓时间
CloseCause string // 平仓原因 ["stoploss", "takeprofit", "trailing", "retrace", "signal"](“止损”、“止盈”、“动态跟踪”、“回撤”、“信号”)
}
type BacktestResult struct {

4
internal/trading/okx/account_holder.go

@ -0,0 +1,4 @@
package okx
type OkxAccountHolder struct {
}

14
pkg/trade/account.go

@ -0,0 +1,14 @@
package trade
import (
"sig-pub/api/pb"
"github.com/govalues/decimal"
)
type IAccountHolder interface {
Exchange() pb.ExchangeType
GetValueCash() decimal.Decimal // 获取账户总市值
GetTradeCash() decimal.Decimal // 获取可交易空闲资金
GetOpenTrades() []int64 // 获取未平仓交易单
}

2
pkg/trader/error.go → pkg/trade/error.go

@ -1,4 +1,4 @@
package trader
package trade
type ErrorCode int32

9
internal/trading/backtest/risk_strategy.go → pkg/trade/risk_strategy.go

@ -1,10 +1,15 @@
package backtest
package trade
import (
"sig-pub/api/pb"
"sig-pub/pkg/indicator"
"sig-pub/pkg/types"
)
type IRickStrategy interface {
OnSingle(signalSide types.Side)
}
// RickStrategy 风险管理策略
type RickStrategy struct {
indicatorCtx indicator.IIndicatorContext
@ -18,5 +23,5 @@ func (s *RickStrategy) OnSingle(signalSide pb.Side) (side pb.Side) {
ts := k.Ts
_, _ = price, ts
return
return signalSide
}

34
pkg/trader/indicator.go

@ -1,34 +0,0 @@
package trader
import (
"sig-pub/pkg/types"
"github.com/govalues/decimal"
)
// 定义
// Dependes() []IndicatorDef // 需要订阅的指标列表(包括k线, 实时k线/关闭k线)
type IndicatorDef struct {
IndicatorName string
Intervals []types.Interval
}
// 指标定义接口
type Indicator interface {
Meta() IndicatorMeta
// init id, 计算完成 publish 时使用id,
// exchange: 封装indicator访问, 封装历史k线访问
// args: 动态指标参数定义, 执行时创建
Init(ctx Context, exchange any, args map[string]any) (code ErrorCode, err error) // 初始化指标参数, 上下文
Update(kline types.Kline) (err error) // 驱动k线数据, 待驱动k线到达后, 再待subscribe计算完成后执行
Emit(func(klineTs int64, indicators map[string]decimal.Decimal)) // 指标计算完成后发送, 由指标执行器进行存储或分发
}
// 窗口函数
type SeriesWindow interface {
Range(count int) // 当前k到
}
// 指标能力
type Context interface {
}

42
pkg/trader/strategy.go

@ -1,42 +0,0 @@
package trader
import "sig-pub/pkg/types"
type StrategyName string
// 下单策略接口
type Strategy interface {
Meta() StrategyMeta
// init id, 计算完成 publish 时使用id,
// exchange: 封装indicator访问, 封装历史k线访问
// args: 动态策略参数, 执行时创建
Init(ctx StrategyContext, args map[string]any) (code ErrorCode, err error)
Update(ctx StrategyContext, kline types.Kline) (code ErrorCode, err error)
// Emit() // 下单: sell/buy -> 持单,双方向?, score(分数权重)
}
type StrategyMeta struct {
// Id string `json:"id"` // 策略注册/执行器系统分配
Name string
Desc string
SubIntervals []types.Interval // 订阅k线周期
}
// KlineServiceClient
// IndicatorClient.Sub(MACD5) stream[Indicator]
// IndicatorClient.Sub(ALMA) stream[Indicator]
//
// 持单策略接口,动态止盈/止损/加仓/减仓
type OrderStrategy interface {
}
// 策略外部访问能力
type StrategyContext interface {
Previous(offset int) types.Kline
Range(offset int) []types.Kline
}
// 策略a
type StrategyA struct {
}

78
pkg/trader/strategy_trend_trace.go

@ -1,78 +0,0 @@
package trader
import (
"fmt"
"sig-pub/pkg/types"
"sig-pub/pkg/types/series"
"sig-pub/pkg/zlog"
"github.com/spf13/cast"
)
// stateful
type StrategyTrendTrace struct {
intervalDatas map[types.Interval]*series.LimitFloats
argBaseLine int
}
func NewStrategyTrendTrace() *StrategyTrendTrace {
return &StrategyTrendTrace{}
}
func (StrategyTrendTrace) Meta() StrategyMeta {
return StrategyMeta{
SubIntervals: []types.Interval{
types.Interval5m, types.Interval15m, types.Interval1d,
},
}
}
func (s *StrategyTrendTrace) initArgs(args map[string]string) (err error) {
return
}
func (s *StrategyTrendTrace) Init(ctx StrategyContext, args map[string]string) (code ErrorCode, err error) {
s.argBaseLine, err = cast.ToIntE(args["baseLine"])
if err != nil {
return
}
if s.argBaseLine <= 0 {
}
s.intervalDatas = map[types.Interval]*series.LimitFloats{
types.Interval5m: series.NewLimitFloats(s.argBaseLine),
types.Interval15m: series.NewLimitFloats(s.argBaseLine),
types.Interval1d: series.NewLimitFloats(s.argBaseLine),
}
return
}
func (s *StrategyTrendTrace) Update(ctx StrategyContext, kline types.Kline) (code ErrorCode, err error) {
data, ok := s.intervalDatas[kline.Interval]
if !ok {
zlog.Warningf("ignore interval kline: %v", kline.Interval)
return
}
v, ok := kline.Close.Float64()
if !ok {
code = ErrorCodeKline
err = fmt.Errorf("kline close value error: %#v", kline)
return
}
data.Push(v)
// calc klines
s.caculate()
return
}
func (s *StrategyTrendTrace) caculate() {
// 5m判断趋势, 15m/1h 确认趋势
datas5m := s.intervalDatas[types.Interval5m]
minV, maxV := datas5m.MinMax()
_, _ = minV, maxV
}

66
pkg/trader/trader_meta.go

@ -1,66 +0,0 @@
package trader
import "github.com/spf13/cast"
// 指标注册/执行器系统分配
// k线频率, 执行时指定
// 指标数据(频率)存储, 实时计算 ?
type IndicatorMeta struct {
Name string
Desc string
Args []Arg
}
type Arg struct {
Name string
Desc string
ArgType ArgType // 参数类型
Options []ArgOption // 单选/多选选项列表
}
type ArgOption struct {
Name string
Desc string
}
// CastValidate 数据类型校验
func (t Arg) CastValidate(v string) bool {
switch t.ArgType {
default:
return false
case ArgTypeString:
return true
case ArgTypeInt:
fallthrough
case ArgTypeUInt:
if r, e := cast.ToIntE(v); e != nil {
return false
} else if t.ArgType == ArgTypeUInt {
return r >= 0
}
return true
case ArgTypeFloat:
fallthrough
case ArgTypeUFloat:
if r, e := cast.ToFloat64E(v); e != nil {
return false
} else if t.ArgType == ArgTypeUFloat {
return r >= 0
}
return true
}
}
// 参数类型
type ArgType int8
const (
_ ArgType = iota
ArgTypeString
ArgTypeInt
ArgTypeUInt
ArgTypeFloat
ArgTypeUFloat
ArgTypeSelect // 单选
ArgTypeCheckBox // 多选
)
Loading…
Cancel
Save