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 ( |
import ( |
||||||
"runtime/debug" |
"runtime/debug" |
||||||
@ -1,4 +1,4 @@ |
|||||||
package lang |
package misc |
||||||
|
|
||||||
// Ternary is a 1 line if/else statement.
|
// Ternary is a 1 line if/else statement.
|
||||||
func Ternary[T any](condition bool, ifOutput T, elseOutput T) T { |
func Ternary[T any](condition bool, ifOutput T, elseOutput T) T { |
||||||
Loading…
Reference in new issue