This commit is contained in:
2026-01-09 15:48:31 +08:00
parent e32eabbf95
commit c8e189e9c7
28 changed files with 2795 additions and 0 deletions

123
trade/calc_tech.go Normal file
View File

@@ -0,0 +1,123 @@
package trade
import (
"fmt"
"math"
"git.apinb.com/quant/strategy/types"
"github.com/markcheno/go-talib"
"github.com/shopspring/decimal"
)
// 计算合约的利润:多头
func CalculateProfit_Long(openPrice decimal.Decimal, currentPrice decimal.Decimal, quantity decimal.Decimal) decimal.Decimal {
// 多头头寸:利润 = (当前价 - 开仓价) * 数量
return (currentPrice.Sub(openPrice)).Mul(quantity)
}
// 计算合约的利润:空头
func CalculateProfit_Short(openPrice decimal.Decimal, currentPrice decimal.Decimal, quantity decimal.Decimal) decimal.Decimal {
// 空头头寸:利润 = (开仓价 - 当前价) * 数量
return (openPrice.Sub(currentPrice)).Mul(quantity)
}
// 这个方法的逻辑是合理的:它对输入的 value 进行“降噪”处理,只有当绝对值大于等于 threshold 时才认为有意义,否则视为 0。
// 然后根据降噪后的值判断正负性。
// threshold 由调用方传入,灵活性较高。
// 但注释有误,应该是“输入值绝对值小于 threshold 时视为0”而不是 0.03。
// 返回值语义清晰1 表示正,-1 表示负0 表示零。
func DenoiseAndJudge(value, threshold float64) int {
if math.Abs(value) < threshold {
return 0
}
if value > 0 {
return 1
}
if value < 0 {
return -1
}
return 0
}
// isOutOfRange 判断传入的 float64 是否大于 0.001 或小于 -0.001
func IsOutOfRange(f float64) int {
if f >= 0.001 {
return 1
}
if f <= -0.001 {
return -1
}
return 0
}
func EMA(inReal []float64, inTimePeriod int, round int) []float64 {
var newResult []float64
emaResult := talib.Ema(inReal, inTimePeriod)
for _, val := range emaResult {
if val == 0 {
continue
}
newResult = append(newResult, FloatRound(val, round))
}
return newResult
}
func ATR(k []*types.KLine, period int) float64 {
high := make([]float64, len(k))
low := make([]float64, len(k))
closes := make([]float64, len(k))
for _, line := range k {
high = append(high, line.High)
low = append(low, line.Low)
closes = append(closes, line.Close)
}
atr := talib.Atr(high, low, closes, period)
return atr[len(atr)-1]
}
func CheckCross(emaFast, emaSlow []float64, MinCrossStrength float64) (bool, string, string) {
if len(emaFast) != 2 || len(emaSlow) != 2 {
return false, "", "参数错误,emaFast或emaSlow长度必须为2"
}
// 检查是否有交叉
prevDiff := emaFast[0] - emaSlow[0] // 前一个点的差值
currentDiff := emaFast[1] - emaSlow[1] // 当前点的差值
// 检查是否有交叉(从负到正或从正到负)
if prevDiff*currentDiff >= 0 {
return false, "", "无交叉:" + fmt.Sprintf("prevDiff: %f, currentDiff: %f", prevDiff, currentDiff)
}
// 降噪:检查交叉强度是否足够大
diffChange := currentDiff - prevDiff
if abs(diffChange) < MinCrossStrength {
return false, "", "交叉强度太小,可能是噪音:" + fmt.Sprintf("diffChange: %f, MinCrossStrength: %f", diffChange, MinCrossStrength)
}
// 简化的趋势判断 - 放宽过于严格的条件
var trend string
if currentDiff > 0 {
// 快线上穿慢线,判断为上升趋势
// 不再要求快线和慢线都必须同时上升因为EMA交叉本身就表明趋势变化
trend = "UP"
} else {
// 快线下穿慢线,判断为下降趋势
// 不再要求快线和慢线都必须同时下降因为EMA交叉本身就表明趋势变化
trend = "DOWN"
}
return true, trend, ""
}
// 辅助函数:计算绝对值
func abs(x float64) float64 {
if x < 0 {
return -x
}
return x
}