124 lines
3.5 KiB
Go
124 lines
3.5 KiB
Go
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
|
||
}
|