19 changed files with 255 additions and 65 deletions
@ -0,0 +1,97 @@
|
||||
package strategy |
||||
|
||||
import ( |
||||
"sig-pub/pkg/types" |
||||
) |
||||
|
||||
// BollGrid 布林带网格策略
|
||||
// 基于布林带中轨(SMA)和标准差(StdDev)构建动态网格
|
||||
// 利用布林带指标计算出的中轨和上轨反推标准差
|
||||
// 当价格下穿下方网格线时做多
|
||||
// 当价格上穿上方网格线时做空
|
||||
type BollGrid struct { |
||||
period int16 // 布林带周期
|
||||
gridStep float64 // 网格间距(标准差倍数)
|
||||
gridSize int16 // 单侧网格数量
|
||||
} |
||||
|
||||
func (s *BollGrid) New() ISigStrategy { |
||||
return &BollGrid{} |
||||
} |
||||
|
||||
func (s *BollGrid) Meta() StrategyMeta { |
||||
return StrategyMeta{ |
||||
Name: "BollGrid", |
||||
Desc: "基于布林带标准差的动态网格策略", |
||||
Input: []types.InputArg{ |
||||
{Name: "period", Type: types.InputTypeUInt, Desc: "布林带周期", Default: 20}, |
||||
{Name: "gridStep", Type: types.InputTypeUFloat, Desc: "网格间距(标准差倍数)", Default: 1.0}, |
||||
{Name: "gridSize", Type: types.InputTypeUInt, Desc: "单侧网格数量", Default: 3}, |
||||
}, |
||||
} |
||||
} |
||||
|
||||
func (s *BollGrid) Init(input types.Input) (err error) { |
||||
s.period = input.Int16("period") |
||||
s.gridStep = input.Float("gridStep") |
||||
s.gridSize = input.Int16("gridSize") |
||||
return |
||||
} |
||||
|
||||
func (s *BollGrid) CandlePeriods(ctx ISingleSigStrategyContext) int16 { |
||||
return max( |
||||
ctx.Indicator("BOLL", s.period).CandlePeriods(), |
||||
2, // 需要前一根K线判断交叉
|
||||
) |
||||
} |
||||
|
||||
func (s *BollGrid) Update(ctx ISingleSigStrategyContext) (side types.Side) { |
||||
// 获取指标数据
|
||||
// BOLL指标 Calculate 返回值为 mb (中轨)
|
||||
bollInd := ctx.Indicator("BOLL", s.period) |
||||
mb := bollInd.Get(0) |
||||
ub := bollInd.State("ub", 0) // 上轨 (mb + 2*sigma)
|
||||
|
||||
// 计算标准差 sigma
|
||||
// 默认 BOLL 实现中,ub = mb + 2 * sigma
|
||||
sigma := (ub - mb) / 2.0 |
||||
if sigma == 0 { |
||||
return types.SideNone |
||||
} |
||||
|
||||
// 获取前一根指标数据用于判断交叉
|
||||
mbPrev := bollInd.Get(1) |
||||
ubPrev := bollInd.State("ub", 1) |
||||
sigmaPrev := (ubPrev - mbPrev) / 2.0 |
||||
|
||||
// 获取K线收盘价
|
||||
closeP := ctx.Get(0).CloseF64() |
||||
closePrev := ctx.Get(1).CloseF64() |
||||
|
||||
// 遍历网格层级
|
||||
for i := int16(1); i <= s.gridSize; i++ { |
||||
stepMul := float64(i) * s.gridStep |
||||
|
||||
// 下方网格线: MB - i * step * sigma
|
||||
lower := mb - sigma*stepMul |
||||
lowerPrev := mbPrev - sigmaPrev*stepMul |
||||
|
||||
// 价格下穿下方网格线 -> 买入信号
|
||||
// Close[1] >= Lower[1] && Close[0] < Lower[0]
|
||||
if closePrev >= lowerPrev && closeP < lower { |
||||
return types.SideLong |
||||
} |
||||
|
||||
// 上方网格线: MB + i * step * sigma
|
||||
upper := mb + sigma*stepMul |
||||
upperPrev := mbPrev + sigmaPrev*stepMul |
||||
|
||||
// 价格上穿上方网格线 -> 卖出信号
|
||||
// Close[1] <= Upper[1] && Close[0] > Upper[0]
|
||||
if closePrev <= upperPrev && closeP > upper { |
||||
return types.SideShort |
||||
} |
||||
} |
||||
|
||||
return |
||||
} |
||||
@ -0,0 +1,87 @@
|
||||
package strategy |
||||
|
||||
import ( |
||||
"sig-pub/pkg/types" |
||||
) |
||||
|
||||
// Grid 网格策略
|
||||
// 基于均线和ATR构建动态网格
|
||||
// 当价格下穿下方网格线时做多
|
||||
// 当价格上穿上方网格线时做空
|
||||
type Grid struct { |
||||
period int16 // 均线和ATR周期
|
||||
gridStep float64 // 网格间距(ATR倍数)
|
||||
gridSize int16 // 单侧网格数量
|
||||
} |
||||
|
||||
func (s *Grid) New() ISigStrategy { |
||||
return &Grid{} |
||||
} |
||||
|
||||
func (s *Grid) Meta() StrategyMeta { |
||||
return StrategyMeta{ |
||||
Name: "Grid", |
||||
Desc: "基于ATR的动态网格策略", |
||||
Input: []types.InputArg{ |
||||
{Name: "period", Type: types.InputTypeUInt, Desc: "EMA和ATR周期", Default: 20}, |
||||
{Name: "gridStep", Type: types.InputTypeUFloat, Desc: "网格间距(ATR倍数)", Default: 1.0}, |
||||
{Name: "gridSize", Type: types.InputTypeUInt, Desc: "单侧网格数量", Default: 5}, |
||||
}, |
||||
} |
||||
} |
||||
|
||||
func (s *Grid) Init(input types.Input) (err error) { |
||||
s.period = input.Int16("period") |
||||
s.gridStep = input.Float("gridStep") |
||||
s.gridSize = input.Int16("gridSize") |
||||
return |
||||
} |
||||
|
||||
func (s *Grid) CandlePeriods(ctx ISingleSigStrategyContext) int16 { |
||||
return max( |
||||
ctx.Indicator("EMA", s.period).CandlePeriods(), |
||||
ctx.Indicator("ATR", s.period).CandlePeriods(), |
||||
2, // 需要前一根K线判断交叉
|
||||
) |
||||
} |
||||
|
||||
func (s *Grid) Update(ctx ISingleSigStrategyContext) (side types.Side) { |
||||
// 获取指标数据
|
||||
ema := ctx.Indicator("EMA", s.period).Get(0) |
||||
atr := ctx.Indicator("ATR", s.period).Get(0) |
||||
|
||||
// 获取前一根指标数据用于判断交叉
|
||||
emaPrev := ctx.Indicator("EMA", s.period).Get(1) |
||||
atrPrev := ctx.Indicator("ATR", s.period).Get(1) |
||||
|
||||
// 获取K线收盘价
|
||||
closeP := ctx.Get(0).CloseF64() |
||||
closePrev := ctx.Get(1).CloseF64() |
||||
|
||||
// 遍历网格层级
|
||||
for i := int16(1); i <= s.gridSize; i++ { |
||||
step := float64(i) * s.gridStep |
||||
|
||||
// 下方网格线
|
||||
lower := ema - atr*step |
||||
lowerPrev := emaPrev - atrPrev*step |
||||
|
||||
// 价格下穿下方网格线 -> 买入信号
|
||||
// Close[1] >= Lower[1] && Close[0] < Lower[0]
|
||||
if closePrev >= lowerPrev && closeP < lower { |
||||
return types.SideLong |
||||
} |
||||
|
||||
// 上方网格线
|
||||
upper := ema + atr*step |
||||
upperPrev := emaPrev + atrPrev*step |
||||
|
||||
// 价格上穿上方网格线 -> 卖出信号
|
||||
// Close[1] <= Upper[1] && Close[0] > Upper[0]
|
||||
if closePrev <= upperPrev && closeP > upper { |
||||
return types.SideShort |
||||
} |
||||
} |
||||
|
||||
return |
||||
} |
||||
@ -1,4 +1,4 @@
|
||||
package lang |
||||
package misc |
||||
|
||||
import ( |
||||
"runtime/debug" |
||||
@ -1,4 +1,4 @@
|
||||
package lang |
||||
package misc |
||||
|
||||
// Ternary is a 1 line if/else statement.
|
||||
func Ternary[T any](condition bool, ifOutput T, elseOutput T) T { |
||||
Loading…
Reference in new issue