You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
99 lines
3.3 KiB
99 lines
3.3 KiB
package trade |
|
|
|
import ( |
|
"fmt" |
|
"sig-pub/pkg/strategy" |
|
"sig-pub/pkg/types" |
|
"sig-pub/pkg/types/decimals" |
|
"time" |
|
|
|
"github.com/govalues/decimal" |
|
) |
|
|
|
const ( |
|
PriceDriverInterval = types.Interval1m // 价格更新使用1分钟k线 |
|
) |
|
|
|
type SigTradeStrategy struct { |
|
closeParam *CloseStrategyInput |
|
} |
|
|
|
func NewSigTradeStrategy() *SigTradeStrategy { |
|
return &SigTradeStrategy{} |
|
} |
|
|
|
func (s *SigTradeStrategy) New() strategy.ISigStrategy { |
|
return &SigTradeStrategy{} |
|
} |
|
|
|
func (s *SigTradeStrategy) Meta() strategy.StrategyMeta { |
|
return strategy.StrategyMeta{ |
|
Name: "SigTradeStrategy", |
|
Desc: "默认交易策略", |
|
Input: []types.InputArg{ |
|
// 交易参数 |
|
{Name: "maxPosPct", Type: types.InputTypeUFloat, Desc: "单笔交易最大仓位占比"}, |
|
{Name: "maxExposurePct", Type: types.InputTypeUFloat, Desc: "最大总敞口占比"}, |
|
{Name: "maxLots", Type: types.InputTypeUInt, Desc: "最大手数/数量"}, |
|
// 平仓止损参数 |
|
{Name: "stopLossPct", Type: types.InputTypeUFloat, Desc: "固定止损比例"}, |
|
{Name: "takeProfitPct", Type: types.InputTypeUFloat, Desc: "固定止盈比例"}, |
|
{Name: "profitRetracePcts", Type: types.InputTypeUFloats2D, Desc: "基于最高利润回撤触发平仓 (例如 [[0.01, 0.3], [0.02, 0.2]] 最高利润超过1%时30%回撤则触发平仓, 最高利润超过2%时20%回撤就触发平仓)"}, |
|
{Name: "closeOnSideReverse", Type: types.InputTypeBool, Desc: "交易信号和持单方向相反时是否进行平仓"}, |
|
{Name: "fee", Type: types.InputTypeBool, Desc: "计算止盈止损时是否包含手续费"}, |
|
// 风险评估参数... |
|
}, |
|
} |
|
} |
|
|
|
// 校验参数, 并根据参数初始化策略 |
|
func (s *SigTradeStrategy) Init(input types.Input) (err error) { |
|
s.closeParam = new(CloseStrategyInput) |
|
input.DecodeInput(s.closeParam) |
|
if s.closeParam.StopLossPct < 0 { |
|
err = fmt.Errorf("stopLossPct can't less zero") |
|
return |
|
} |
|
return |
|
} |
|
|
|
// 需要的各周期最小数据k线数 |
|
func (s *SigTradeStrategy) CandlePeriods(ctx strategy.IInstanceIntervalSigStrategyContext) (tradeInsts []string, iPeriods *types.IntervalState[int16]) { |
|
iPeriods = types.NewIntervalState[int16]() |
|
iPeriods.Set(PriceDriverInterval, 1) |
|
return |
|
} |
|
|
|
// RishAssess 信号风险评估, 是否进行交易 |
|
func (s *SigTradeStrategy) RishAssess(ctx strategy.IInstanceIntervalSigStrategyContext, account ITradeAccount, sigInstId string, sigSide types.Side) (doTrade bool, cause Cause, err error) { |
|
|
|
return true, 0, nil |
|
} |
|
|
|
// TradeAssess 生成下单参数(交易量/方向/杠杆) |
|
// 控制滑点, 仓位管理 |
|
// 持仓中币种不能改变杠杆 |
|
func (s *SigTradeStrategy) TradeAssess(ctx strategy.IInstanceIntervalSigStrategyContext, account ITradeAccount, sigInstId string, sigSide types.Side) (tickets []TradeTicket, err error) { |
|
if pos := account.GetPosition(sigInstId); pos != nil { |
|
// 已持仓不能下反方向单, todo 副账户做反方向单,对冲(viceAccount) |
|
if pos.Side != sigSide { |
|
return |
|
} |
|
} |
|
|
|
k := ctx.Get(sigInstId, PriceDriverInterval, 0) |
|
price := decimals.MustToFloat64(k.Close) |
|
ta := TradeTicket{ |
|
TradeType: TradeTypeOpen, |
|
InstId: sigInstId, |
|
Side: sigSide, |
|
Price: price, |
|
Leverage: 1, |
|
Qty: decimal.MustParse("0.02"), |
|
Interval: string(k.Interval), |
|
Ktime: k.Interval.MustAddMul(k.Ts, 1), |
|
Ctime: time.Now().UnixMilli(), |
|
} |
|
tickets = append(tickets, ta) |
|
return |
|
}
|
|
|