Browse Source

multi trade inst

main
strange 9 months ago
parent
commit
5358849edd
  1. 1
      README.md
  2. 4
      config/exchange.toml
  3. 123
      internal/trading/backtest/sig_strategy_backtester.go
  4. 5
      internal/trading/backtest/trading_plan_backtester.go
  5. 40
      internal/trading/sig/indicator_context.go
  6. 4
      internal/trading/sig/strategy_context.go
  7. 10
      internal/trading/trading_service.go
  8. 2
      pkg/strategy/mul_inst_rank.go
  9. 2
      pkg/strategy/sig_strategy.go
  10. 2
      pkg/trade/risk_strategy.go
  11. 7
      pkg/trade/trade_account.go
  12. 23
      pkg/trade/types.go
  13. 13
      pkg/types/input.go

1
README.md

@ -132,3 +132,4 @@ RSI[1,2,3,4] -> RSI[0]
[Alphalens 因子评估库](https://github.com/quantopian/alphalens) [Alphalens 因子评估库](https://github.com/quantopian/alphalens)
[词法解析](https://github.com/alecthomas/participle)

4
config/exchange.toml

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

123
internal/trading/backtest/sig_strategy_backtester.go

@ -49,10 +49,11 @@ func (b *SigStrategyBacktester) SubKline(instId string, interval types.Interval,
} }
// Backtest 基于历史数据回测信号策略 // Backtest 基于历史数据回测信号策略
func (b *SigStrategyBacktester) Backtest(ctx context.Context, sigStrategyInput types.Input, sr *pb.SeriesRange, func (b *SigStrategyBacktester) Backtest(ctx context.Context,
// cleanIntervalSeries *types.IntervalState[*types.KlineSeries], sigStrategyInput types.Input,
sr *pb.SeriesRange,
iiks *types.InstanceIntervalKlineSeries, iiks *types.InstanceIntervalKlineSeries,
recvSignal func(sigSide types.Side, k types.Kline) (err error), recvSignal func(instId string, sigSide types.Side, k types.Kline) (err error),
) (err error) { ) (err error) {
if iiks == nil { if iiks == nil {
iiks = types.NewInstanceIntervalKlineSeries() iiks = types.NewInstanceIntervalKlineSeries()
@ -68,7 +69,7 @@ func (b *SigStrategyBacktester) Backtest(ctx context.Context, sigStrategyInput t
case strategy.SigStrategyTypeInterval: case strategy.SigStrategyTypeInterval:
err = b.intervalStrategySeries(ctx, b.sigStrategy.(strategy.IIntervalSigStrategy), sigStrategyInput, sr, iiks, recvSignal) err = b.intervalStrategySeries(ctx, b.sigStrategy.(strategy.IIntervalSigStrategy), sigStrategyInput, sr, iiks, recvSignal)
case strategy.SigStrategyTypeInstanceInterval: case strategy.SigStrategyTypeInstanceInterval:
// todo err = b.instanceIntervalStrategySeries(ctx, b.sigStrategy.(strategy.IInstanceIntervalSigStrategy), sigStrategyInput, sr, iiks, recvSignal)
default: default:
err = fmt.Errorf("unknown sig strategy type %v", b.sigStrategyType) err = fmt.Errorf("unknown sig strategy type %v", b.sigStrategyType)
} }
@ -76,7 +77,13 @@ func (b *SigStrategyBacktester) Backtest(ctx context.Context, sigStrategyInput t
} }
// singleStrategySeries 单周期策略 // singleStrategySeries 单周期策略
func (b *SigStrategyBacktester) singleStrategySeries(ctx context.Context, sigStrategy strategy.ISingleSigStrategy, sigStrategyInput types.Input, sr *pb.SeriesRange, iiks *types.InstanceIntervalKlineSeries, recvSignal func(sigSide types.Side, k types.Kline) (err error)) (err error) { func (b *SigStrategyBacktester) singleStrategySeries(ctx context.Context,
sigStrategy strategy.ISingleSigStrategy,
sigStrategyInput types.Input,
sr *pb.SeriesRange,
iiks *types.InstanceIntervalKlineSeries,
recvSignal func(instId string, sigSide types.Side, k types.Kline) (err error),
) (err error) {
driverInstId := sr.InstId driverInstId := sr.InstId
driverInterval := types.Interval(sr.Interval) driverInterval := types.Interval(sr.Interval)
driverSeries := iiks.Get(driverInstId, driverInterval) driverSeries := iiks.Get(driverInstId, driverInterval)
@ -95,7 +102,7 @@ func (b *SigStrategyBacktester) singleStrategySeries(ctx context.Context, sigStr
} }
sigSide := sigStrategy.Update(strategyContext) sigSide := sigStrategy.Update(strategyContext)
if sigSide.IsValid() { if sigSide.IsValid() {
if err = recvSignal(sigSide, *k); err != nil { if err = recvSignal(driverInstId, sigSide, *k); err != nil {
return return
} }
} }
@ -105,7 +112,13 @@ func (b *SigStrategyBacktester) singleStrategySeries(ctx context.Context, sigStr
} }
// intervalStrategySeries 多周期策略 // intervalStrategySeries 多周期策略
func (b *SigStrategyBacktester) intervalStrategySeries(ctx context.Context, intervalSigStrategy strategy.IIntervalSigStrategy, sigStrategyInput types.Input, sr *pb.SeriesRange, iiks *types.InstanceIntervalKlineSeries, recvSignal func(sigSide types.Side, k types.Kline) (err error)) (err error) { func (b *SigStrategyBacktester) intervalStrategySeries(ctx context.Context,
intervalSigStrategy strategy.IIntervalSigStrategy,
sigStrategyInput types.Input,
sr *pb.SeriesRange,
iiks *types.InstanceIntervalKlineSeries,
recvSignal func(instId string, sigSide types.Side, k types.Kline) (err error),
) (err error) {
driverInstId := sr.InstId driverInstId := sr.InstId
driverInterval := types.Interval(sr.Interval) driverInterval := types.Interval(sr.Interval)
intervalKlineSeries := iiks.GetIntervalKlineSeries(driverInstId) intervalKlineSeries := iiks.GetIntervalKlineSeries(driverInstId)
@ -114,51 +127,81 @@ func (b *SigStrategyBacktester) intervalStrategySeries(ctx context.Context, inte
// 各周期所需k线数量 // 各周期所需k线数量
intervalCandlePeriods := intervalSigStrategy.CandlePeriods(intervalStrategyContext) intervalCandlePeriods := intervalSigStrategy.CandlePeriods(intervalStrategyContext)
periodsChecked := false
err = b.multiInstanceIntervalSeries(ctx, sr, []string{sr.InstId}, intervalCandlePeriods, iiks, func(driver bool, instId string, interval types.Interval, k *types.Kline) (err error) { err = b.multiInstanceIntervalSeries(ctx, sr, []string{sr.InstId}, intervalCandlePeriods, iiks, func(driver bool, instId string, interval types.Interval, k *types.Kline) (err error) {
if !driver || instId != driverInstId || interval != driverInterval { if !driver || instId != driverInstId || interval != driverInterval {
return return
} }
update := true // 策略所需周期窗口是否满足检查
intervalCandlePeriods.Range(func(interval types.Interval, require int16) { if !periodsChecked {
if update && require > 0 { update := true
series := intervalKlineSeries.Get(interval) intervalCandlePeriods.Range(func(interval types.Interval, require int16) {
update = series.Length() >= int(require) if update && require > 0 {
series := intervalKlineSeries.Get(interval)
update = series.Length() >= int(require)
}
})
if !update {
return
} }
}) periodsChecked = true
if !update {
return
} }
sigSide := intervalSigStrategy.Update(intervalStrategyContext) sigSide := intervalSigStrategy.Update(intervalStrategyContext)
if sigSide.IsValid() { if sigSide.IsValid() {
if err = recvSignal(sigSide, *k); err != nil { if err = recvSignal(driverInstId, sigSide, *k); err != nil {
return return
} }
} }
return return
}) })
return
}
// instanceIntervalStrategySeries 多币种多周期策略
func (b *SigStrategyBacktester) instanceIntervalStrategySeries(ctx context.Context,
intervalSigStrategy strategy.IInstanceIntervalSigStrategy,
sigStrategyInput types.Input,
sr *pb.SeriesRange,
iiks *types.InstanceIntervalKlineSeries,
recvSignal func(instId string, sigSide types.Side, k types.Kline) (err error),
) (err error) {
driverInstId := sr.InstId
driverInterval := types.Interval(sr.Interval)
// err = b.multiIntervalSeries(ctx, sr, intervalCandlePeriods, intervalKlineSeries, func(driver bool, interval types.Interval, k *types.Kline) (err error) { // 策略上下文
// if !driver { strategyContext := sig.NewInstanceIntervalSigStrategyContext(sigStrategyInput, iiks, b.indicatorReg)
// return // 各周期所需k线数量
// } tradeInsts, intervalCandlePeriods := intervalSigStrategy.CandlePeriods(strategyContext)
// update := true
// intervalCandlePeriods.Range(func(interval types.Interval, require int16) { periodsChecked := false
// if update && require > 0 { err = b.multiInstanceIntervalSeries(ctx, sr, tradeInsts, intervalCandlePeriods, iiks, func(driver bool, instId string, interval types.Interval, k *types.Kline) (err error) {
// series := intervalKlineSeries.Get(interval) if !driver || instId != driverInstId || interval != driverInterval {
// update = series.Length() >= int(require) return
// } }
// }) // 策略所需周期窗口是否满足检查
// if !update { if !periodsChecked {
// return update := true
// } for _, instId := range tradeInsts {
// sigSide := intervalSigStrategy.Update(intervalStrategyContext) intervalCandlePeriods.Range(func(interval types.Interval, periods int16) {
// if sigSide.IsValid() { if update && periods > 0 {
// if err = recvSignal(sigSide, *k); err != nil { series := iiks.Get(instId, interval)
// return update = series.Length() >= int(periods)
// } }
// } })
// return if !update {
// }) return
}
}
periodsChecked = true
}
sigSideInsts := intervalSigStrategy.Update(strategyContext)
for _, si := range sigSideInsts {
if err = recvSignal(si.InstId, si.Side, *k); err != nil {
return
}
}
return
})
return return
} }
@ -266,7 +309,7 @@ func (b *SigStrategyBacktester) multiInstanceIntervalSeries(ctx context.Context,
} }
return return
}) })
zlog.Debugf("other sr finish with: %s(%s), %v", isr.InstId, isr.Interval, err1) zlog.Debugf("other sr finish with: %s(%s), %v, last=%d", isr.InstId, isr.Interval, err1, intervalAdder(kSeries.MustGet(0).Ts, 1))
if err1 == nil { if err1 == nil {
syncCh <- -1 // 通知更新完毕, 后续不再更新 syncCh <- -1 // 通知更新完毕, 后续不再更新
} else if err1 != errStop { } else if err1 != errStop {
@ -317,7 +360,7 @@ func (b *SigStrategyBacktester) multiInstanceIntervalSeries(ctx context.Context,
} }
return recvFn(true, driverInstId, driverInterval, k) return recvFn(true, driverInstId, driverInterval, k)
}) })
zlog.Debugf("driver sr finish with: %s(%s), %v,", sr.InstId, sr.Interval, err0) zlog.Debugf("driver sr finish with: %s(%s), %v, last=%d", sr.InstId, sr.Interval, err0, driverIntervalAdder(driverSeries.MustGet(0).Ts, 1))
if err0 == nil { if err0 == nil {
close(stopCh) close(stopCh)
} else if err0 != errStop { } else if err0 != errStop {

5
internal/trading/backtest/trading_plan_backtester.go

@ -112,7 +112,7 @@ func (b *TradingPlanBacktester) Backtest(ctx context.Context, sr *pb.SeriesRange
}) })
iiks := types.NewInstanceIntervalKlineSeries() iiks := types.NewInstanceIntervalKlineSeries()
err = sigStrategyBacktester.Backtest(ctx, b.sigStrategyInput, sr, iiks, func(sigSide types.Side, k types.Kline) (err error) { err = sigStrategyBacktester.Backtest(ctx, b.sigStrategyInput, sr, iiks, func(instId string, sigSide types.Side, k types.Kline) (err error) {
test.Singals++ test.Singals++
// 根据交易信号检查仓位平仓 // 根据交易信号检查仓位平仓
if err = b.closeBySigSingal(sigSide, k); err != nil { if err = b.closeBySigSingal(sigSide, k); err != nil {
@ -213,7 +213,8 @@ func (b *TradingPlanBacktester) closeBySigSingal(sigSide types.Side, kline types
// onSideSingal 出现买卖信号 // onSideSingal 出现买卖信号
func (b *TradingPlanBacktester) onSideSingal(sigSide types.Side, k types.Kline) (err error) { func (b *TradingPlanBacktester) onSideSingal(sigSide types.Side, k types.Kline) (err error) {
// 买卖信号交易风险分析 // 买卖信号交易风险分析
doTrade, causes, err := b.riskStrategy.SigRiskAnalyze(sigSide)
doTrade, causes, err := b.riskStrategy.SigRiskAnalyze(b.account, sigSide)
if err != nil { if err != nil {
return return
} }

40
internal/trading/sig/indicator_context.go

@ -28,33 +28,37 @@ type IOffsetIndicatorContext interface {
// IndicatorContext 指标上下文, 提供k线序列给指标计算使用 // IndicatorContext 指标上下文, 提供k线序列给指标计算使用
type IndicatorContext struct { type IndicatorContext struct {
IOffsetIndicatorContext IOffsetIndicatorContext
indicator indicator.IIndicator indicator indicator.IIndicator
indicatorStateKey string indicatorKey string
indicatorsReg *indicator.IndicatorRegistry indicatorsReg *indicator.IndicatorRegistry
input types.Input input types.Input
indicatorStates map[string]*IndicatorState // {macd{window:0,fast:9,slow:21,single:10}: state} 初始化时与KlineSeries周期同步 indicatorStates map[string]*IndicatorState // {macd{window:0,fast:9,slow:21,single:10}: state} 初始化时与KlineSeries周期同步
kSeries *types.KlineSeries kSeries *types.KlineSeries
offset int16 offset int16
indicatorTrace []string // 指标调用链避免指标循环引用 indicatorTrace []string // 指标调用链避免指标循环引用
} }
func NewIndicatorContext(indicator indicator.IIndicator, input types.Input, indicatorStates IndicatorStates, kSeries *types.KlineSeries, indicatorsReg *indicator.IndicatorRegistry) *IndicatorContext { func NewIndicatorContext(indicator indicator.IIndicator, input types.Input, indicatorStates IndicatorStates, kSeries *types.KlineSeries, indicatorsReg *indicator.IndicatorRegistry) *IndicatorContext {
inputs := collect.Mapping(indicator.Meta().Input, func(in types.InputArg) string { inputs := collect.Mapping(indicator.Meta().Input, func(in types.InputArg) string {
return input.String(in.Name) return input.String(in.Name)
}) })
stateKey := fmt.Sprintf("%s{%s}", indicator.Meta().Name, strings.Join(inputs, ",")) indicatorKey := fmt.Sprintf("%s{%s}", indicator.Meta().Name, strings.Join(inputs, ","))
return &IndicatorContext{ return &IndicatorContext{
indicator: indicator, indicator: indicator,
indicatorStateKey: stateKey, indicatorKey: indicatorKey,
input: input, input: input,
indicatorStates: indicatorStates, indicatorStates: indicatorStates,
kSeries: kSeries, kSeries: kSeries,
indicatorsReg: indicatorsReg, indicatorsReg: indicatorsReg,
indicatorTrace: []string{indicator.Meta().Name}, indicatorTrace: []string{indicator.Meta().Name},
} }
} }
func (c *IndicatorContext) getIndicatorKey() string {
return c.indicatorKey
}
func (c *IndicatorContext) SetOffset(offset int16) { func (c *IndicatorContext) SetOffset(offset int16) {
c.offset = offset c.offset = offset
} }
@ -96,10 +100,10 @@ func (c *IndicatorContext) Series(offset, count int16) (klines types.Klines) {
// 窗口/参数 // 窗口/参数
// tradingPlan -> interval -> context -> {macd{window:0,fast:9,slow:21,single:10}: state, ema21:state} -> state[[ema]{1.1, 1.2}, [ema]{1.3, 1.4}] // tradingPlan -> interval -> context -> {macd{window:0,fast:9,slow:21,single:10}: state, ema21:state} -> state[[ema]{1.1, 1.2}, [ema]{1.3, 1.4}]
func (c *IndicatorContext) State() indicator.IIndicatorState { func (c *IndicatorContext) State() indicator.IIndicatorState {
state, ok := c.indicatorStates[c.indicatorStateKey] state, ok := c.indicatorStates[c.indicatorKey]
if !ok { if !ok {
state = NewIndicatorState(c.kSeries.Interval) state = NewIndicatorState(c.kSeries.Interval)
c.indicatorStates[c.indicatorStateKey] = state c.indicatorStates[c.indicatorKey] = state
// 从头KlineSeries跑一遍, 针对ema,macd等回溯迭代指标, 将state与KlineSeries对齐 // 从头KlineSeries跑一遍, 针对ema,macd等回溯迭代指标, 将state与KlineSeries对齐
c.backtrackIndicatorState(c.indicator) c.backtrackIndicatorState(c.indicator)
} }

4
internal/trading/sig/strategy_context.go

@ -124,10 +124,10 @@ type InstanceIntervalSigStrategyContext struct {
instanceIntervalIndicatorStates *collect.ConcurrentMap[string, *types.IntervalState[IndicatorStates]] instanceIntervalIndicatorStates *collect.ConcurrentMap[string, *types.IntervalState[IndicatorStates]]
} }
func NewInstanceIntervalSigStrategyContext(input types.Input, iis *types.InstanceIntervalKlineSeries, indicatorsReg *indicator.IndicatorRegistry) *InstanceIntervalSigStrategyContext { func NewInstanceIntervalSigStrategyContext(input types.Input, iiks *types.InstanceIntervalKlineSeries, indicatorsReg *indicator.IndicatorRegistry) *InstanceIntervalSigStrategyContext {
return &InstanceIntervalSigStrategyContext{ return &InstanceIntervalSigStrategyContext{
input: input, input: input,
iiks: iis, iiks: iiks,
indicatorsReg: indicatorsReg, indicatorsReg: indicatorsReg,
instanceIntervalIndicatorStates: collect.NewConcurrentMap[string, *types.IntervalState[IndicatorStates]](4, func(s string) string { return s }), instanceIntervalIndicatorStates: collect.NewConcurrentMap[string, *types.IntervalState[IndicatorStates]](4, func(s string) string { return s }),
} }

10
internal/trading/trading_service.go

@ -293,10 +293,14 @@ func (svc *TradingService) StrategySeries(ctx context.Context, req *pb.ReqStrate
// 信号策略参数 // 信号策略参数
sigStrategyInput := types.Input(req.Input.AsMap()) sigStrategyInput := types.Input(req.Input.AsMap())
// 使用回测器回测信号策略
// 使用回测器回测信号 driverInstId := req.Series.InstId
backtester := backtest.NewSigStrategyBacktester(sigStrategyType, sigStrategy, svc.indicatorReg, svc.exchangeClient) backtester := backtest.NewSigStrategyBacktester(sigStrategyType, sigStrategy, svc.indicatorReg, svc.exchangeClient)
err = backtester.Backtest(ctx, sigStrategyInput, req.Series, nil, func(sigSide types.Side, k types.Kline) (err error) { err = backtester.Backtest(ctx, sigStrategyInput, req.Series, nil, func(instId string, sigSide types.Side, k types.Kline) (err error) {
if instId != driverInstId {
// todo 多币种回测
return
}
side := lang.Ternary(sigSide == types.SideLong, pb.Side_BUY, pb.Side_SELL) side := lang.Ternary(sigSide == types.SideLong, pb.Side_BUY, pb.Side_SELL)
rsp.Signal = append(rsp.Signal, side) rsp.Signal = append(rsp.Signal, side)
rsp.Times = append(rsp.Times, k.Ts) rsp.Times = append(rsp.Times, k.Ts)

2
pkg/strategy/mul_inst_rank.go

@ -32,7 +32,7 @@ func (s *MultiInstanceRank) Init(input types.Input) (err error) { // 校验参
return return
} }
func (s *MultiInstanceRank) CandlePeriods(ctx IIntervalSigStrategyContext) (insts []string, iss *types.IntervalState[int16]) { func (s *MultiInstanceRank) CandlePeriods(ctx IInstanceIntervalSigStrategyContext) (insts []string, iss *types.IntervalState[int16]) {
insts = []string{"BTC_USDT", "SOL_USDT"} insts = []string{"BTC_USDT", "SOL_USDT"}
iss = types.NewIntervalState[int16]() iss = types.NewIntervalState[int16]()
iss.Set(types.Interval5m, 1) iss.Set(types.Interval5m, 1)

2
pkg/strategy/sig_strategy.go

@ -62,7 +62,7 @@ type IIntervalSigStrategyContext interface {
type IInstanceIntervalSigStrategy interface { type IInstanceIntervalSigStrategy interface {
ISigStrategy ISigStrategy
// 需要的各周期最小数据k线数, 回测时用 // 需要的各周期最小数据k线数, 回测时用
CandlePeriods(ctx IIntervalSigStrategyContext) (tradeInsts []string, iPeriods *types.IntervalState[int16]) CandlePeriods(ctx IInstanceIntervalSigStrategyContext) (tradeInsts []string, iPeriods *types.IntervalState[int16])
Update(ctx IInstanceIntervalSigStrategyContext) (sides []types.SideInst) Update(ctx IInstanceIntervalSigStrategyContext) (sides []types.SideInst)
} }

2
pkg/trade/risk_strategy.go

@ -31,7 +31,7 @@ func NewRiskStrategy(param RiskStrategyParam) (rs *RiskStrategy, err error) {
// 对交易方向进行信心分数评估, 后续开仓仓位 // 对交易方向进行信心分数评估, 后续开仓仓位
// 1.当前持有反方向单时, 不进行开仓 // 1.当前持有反方向单时, 不进行开仓
// 2.当前持有同方向单时, 根据信心分数评估是否加仓 // 2.当前持有同方向单时, 根据信心分数评估是否加仓
func (s *RiskStrategy) SigRiskAnalyze(signalSide types.Side) (doTrade bool, causes []Cause, err error) { func (s *RiskStrategy) SigRiskAnalyze(account ITradeAccount, signalSide types.Side) (doTrade bool, causes []Cause, err error) {
return true, nil, nil return true, nil, nil
} }

7
pkg/trade/trade_account.go

@ -1,10 +1,13 @@
package trade package trade
import "sig-pub/pkg/types"
// sig -> close strategy // sig -> close strategy
// sig -> risk strategy -> trade strategy -> tarde account // sig -> risk strategy -> trade strategy -> tarde account
// position, trades
type ITradeAccount interface { type ITradeAccount interface {
// 获取未平仓交易单 // 获取未平仓交易单
OpenPositions() []*Position OpenPositions() map[int64]*Position
// 获取未平仓交易单数 // 获取未平仓交易单数
CountOpenPositions() int CountOpenPositions() int
@ -13,7 +16,7 @@ type ITradeAccount interface {
TradeOrder(ta TradeArg) (ok bool, cause Cause, err error) TradeOrder(ta TradeArg) (ok bool, cause Cause, err error)
// 将仓位进行平仓 // 将仓位进行平仓
ClosePosition(*Position, Cause) (err error) ClosePosition(*Position, types.Kline, Cause) (err error)
// // 根据当前价格对仓位进行 mark-to-market,返回账户净值 // // 根据当前价格对仓位进行 mark-to-market,返回账户净值
// GetCurrentEquity() decimal.Decimal // GetCurrentEquity() decimal.Decimal

23
pkg/trade/types.go

@ -41,12 +41,35 @@ func (c Cause) String() string {
// Position 持仓仓位 // Position 持仓仓位
type Position struct { type Position struct {
TradeId int64 // 交易订单id TradeId int64 // 交易订单id
InstId string // 交易产品id
Status int32 // 1.交易中 2.持仓中 3.已平仓 Status int32 // 1.交易中 2.持仓中 3.已平仓
Side types.Side // 交易方向 Side types.Side // 交易方向
Qty float64 // 交易量 Qty float64 // 交易量
EntryPx float64 // 入场价格 EntryPx float64 // 入场价格
EntryTs int64 // 入场时间 EntryTs int64 // 入场时间
PeakPx float64 // highest (for long) or lowest (for short) observed price since entry PeakPx float64 // highest (for long) or lowest (for short) observed price since entry
AvgPx float64 // 平均持仓价格
Fee float64 // 手续费 Fee float64 // 手续费
FeeRate float64 // 手续费率 FeeRate float64 // 手续费率
} }
// TradeOrder 交易订单
type TradeOrder struct {
InstId string // 交易产品id
Status int32 // 1.交易中 2.持仓中 3.已平仓
Ctime int64 // 创建时间
Side types.Side // 交易方向
Qty float64 // 交易量
Price float64 // 开仓价格
Fee float64 // 开仓手续费
Leverage int32 // 杠杆倍数
Time int64 // 开仓时间
// ClosePrice float64 // 平仓价格
// CloseFee float64 // 平仓手续费
// CloseTime int64 // 平仓时间
// CloseCause Cause // 平仓原因
Pnl float64 // 盈利/亏损 pnl = (t.ClosePrice-t.Price)*t.Qty - t.Fee - t.CloseFee
Cash float64 // 平仓后账户净值
HoldTime string // 持仓时间
PeakPx float64 // highest (for long) or lowest (for short) observed price since entry
}

13
pkg/types/input.go

@ -91,16 +91,17 @@ func (in Input) Int16(k string) (v int16) {
} }
func (in Input) String(k string) (v string) { func (in Input) String(k string) (v string) {
if r, ok := in.getCache(k); ok { // cacheK := "str:" + k
if v, ok = r.(string); ok { // if r, ok := in.getCache(cacheK); ok {
return // if v, ok = r.(string); ok {
} // return
} // }
// }
v, err := cast.ToStringE(in.get(k, "string")) v, err := cast.ToStringE(in.get(k, "string"))
if err != nil { if err != nil {
panic(fmt.Errorf("input string parse error: %s", k)) panic(fmt.Errorf("input string parse error: %s", k))
} }
in.setCache(k, v) // in.setCache(cacheK, v)
return return
} }

Loading…
Cancel
Save