Files
coin/trade/calc_tech.go
2026-01-09 15:48:31 +08:00

124 lines
3.5 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
}