计算中间币对逻辑
This commit is contained in:
parent
8f519aa103
commit
e0700e77a9
@ -20,7 +20,7 @@ func formatTimestamp(ts string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
loc, _ := time.LoadLocation("Asia/Shanghai")
|
||||
return time.UnixMilli(millis).In(loc).Format("2006-01-02 15:04:05"), nil
|
||||
return time.UnixMilli(millis).In(loc).Format("2006-01-02T15:04:05+08:00"), nil
|
||||
}
|
||||
|
||||
// CandleList 封装Candle数组并提供序列化方法
|
||||
@ -276,6 +276,113 @@ func (cl *CandleList) ToFluentd() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CalculateCrossPair 计算两个币对的中间币对
|
||||
func (cl *CandleList) CalculateCrossPair(other *CandleList) (*CandleList, error) {
|
||||
// 验证周期是否一致
|
||||
if cl.Period != other.Period {
|
||||
return nil, fmt.Errorf("period mismatch: %s vs %s", cl.Period, other.Period)
|
||||
}
|
||||
|
||||
// 解析币对名称
|
||||
base1, quote1 := parsePair(cl.CoinPair)
|
||||
base2, quote2 := parsePair(other.CoinPair)
|
||||
|
||||
// 验证是否构成交叉币对
|
||||
if quote1 != quote2 {
|
||||
return nil, fmt.Errorf("not a valid cross pair: %s and %s", cl.CoinPair, other.CoinPair)
|
||||
}
|
||||
|
||||
// 创建新的CandleList
|
||||
crossPair := fmt.Sprintf("%s-%s", base1, base2)
|
||||
result := &CandleList{
|
||||
CoinPair: crossPair,
|
||||
Period: cl.Period,
|
||||
}
|
||||
|
||||
fmt.Println("result.CoinPair, result.Period: ", result.CoinPair, result.Period)
|
||||
// 创建时间戳映射
|
||||
clMap := make(map[string]*Candle)
|
||||
for _, candle := range cl.Candles {
|
||||
clMap[candle.Timestamp] = candle
|
||||
}
|
||||
|
||||
// 遍历另一个CandleList,寻找匹配的时间戳
|
||||
for _, otherCandle := range other.Candles {
|
||||
if clCandle, exists := clMap[otherCandle.Timestamp]; exists {
|
||||
// 计算中间币对的价格
|
||||
open, err := calculateCrossPrice(clCandle.Open, otherCandle.Open)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
high, err := calculateCrossPrice(clCandle.High, otherCandle.High)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
low, err := calculateCrossPrice(clCandle.Low, otherCandle.Low)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
close, err := calculateCrossPrice(clCandle.Close, otherCandle.Close)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 创建新的Candle
|
||||
crossCandle := &Candle{
|
||||
Timestamp: otherCandle.Timestamp,
|
||||
Open: open,
|
||||
High: high,
|
||||
Low: low,
|
||||
Close: close,
|
||||
Volume: "0", // 成交量不直接转换
|
||||
VolumeCcy: "0", // 成交量不直接转换
|
||||
}
|
||||
|
||||
result.Candles = append(result.Candles, crossCandle)
|
||||
}
|
||||
}
|
||||
|
||||
if len(result.Candles) == 0 {
|
||||
return nil, fmt.Errorf("no overlapping timestamps found")
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// parsePair 解析币对名称
|
||||
func parsePair(pair string) (string, string) {
|
||||
parts := strings.Split(pair, "-")
|
||||
if len(parts) != 2 {
|
||||
return "", ""
|
||||
}
|
||||
return parts[0], parts[1]
|
||||
}
|
||||
|
||||
// calculateCrossPrice 计算交叉币对价格
|
||||
func calculateCrossPrice(price1, price2 string) (string, error) {
|
||||
p1, err := strconv.ParseFloat(price1, 64)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid price1: %v", err)
|
||||
}
|
||||
p2, err := strconv.ParseFloat(price2, 64)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid price2: %v", err)
|
||||
}
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid price2: %v", err)
|
||||
}
|
||||
|
||||
if p2 == 0 {
|
||||
return "", fmt.Errorf("division by zero")
|
||||
}
|
||||
|
||||
result := p1 / p2
|
||||
return fmt.Sprintf("%.8f", result), nil
|
||||
}
|
||||
|
||||
// parsePeriod 将周期字符串转换为time.Duration
|
||||
func parsePeriod(period string) (time.Duration, error) {
|
||||
switch period {
|
||||
@ -374,7 +481,7 @@ func (cl *CandleList) ToElastic() error {
|
||||
|
||||
// 构造记录
|
||||
record := map[string]interface{}{
|
||||
"dataTime": cstTime.Format("2006-01-02 15:04:05"),
|
||||
"dataTime": cstTime.Format("2006-01-02T15:04:05") + "+08:00",
|
||||
"open": candle.Open,
|
||||
"high": candle.High,
|
||||
"low": candle.Low,
|
||||
|
@ -1,12 +0,0 @@
|
||||
=== RUN TestCandleList_ToJson
|
||||
lens of allCandles: 400
|
||||
Number of candles: 400
|
||||
candleList_test.go:29: JSON output written to /tmp/candle_test.json
|
||||
--- PASS: TestCandleList_ToJson (1.74s)
|
||||
=== RUN TestCandleList_ToCsv
|
||||
lens of allCandles: 400
|
||||
Number of candles: 400
|
||||
candleList_test.go:51: CSV output written to /tmp/candle_test.csv
|
||||
--- PASS: TestCandleList_ToCsv (1.02s)
|
||||
PASS
|
||||
ok command-line-arguments 3.293s
|
@ -63,14 +63,40 @@ import (
|
||||
// t.Fatalf("ToEs failed: %v", err)
|
||||
// }
|
||||
// }
|
||||
func TestCandleList_ToElastic(t *testing.T) {
|
||||
startTime := time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
endTime := time.Date(2023, 12, 31, 0, 0, 0, 0, time.UTC)
|
||||
cl, err := MakeCandleList("BTC-USDT", "1D", startTime, endTime, 50)
|
||||
|
||||
// func TestCandleList_ToElastic(t *testing.T) {
|
||||
// startTime := time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
// endTime := time.Date(2025, 3, 1, 0, 0, 0, 0, time.UTC)
|
||||
// cl, err := MakeCandleList("BTC-USDT", "1D", startTime, endTime, 50)
|
||||
// if err != nil {
|
||||
// t.Fatalf("ToEs failed: %v", err)
|
||||
// }
|
||||
// err = cl.ToElastic()
|
||||
// if err != nil {
|
||||
// t.Fatalf("ToEs failed: %v", err)
|
||||
// }
|
||||
// }
|
||||
|
||||
func TestCandleListI_CalculateCrossPair(t *testing.T) {
|
||||
startTime := time.Date(2025, 3, 15, 0, 0, 0, 0, time.UTC)
|
||||
endTime := time.Date(2025, 3, 19, 23, 0, 0, 0, time.UTC)
|
||||
okbUsdt, err := MakeCandleList("OKB-USDT", "4H", startTime, endTime, 50)
|
||||
if err != nil {
|
||||
t.Fatalf("ToEs failed: %v", err)
|
||||
}
|
||||
err = cl.ToElastic()
|
||||
ethUsdt, err := MakeCandleList("ETH-USDT", "4H", startTime, endTime, 50)
|
||||
if err != nil {
|
||||
t.Fatalf("ToEs failed: %v", err)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("ToEs failed: %v", err)
|
||||
}
|
||||
|
||||
okbEth, err := okbUsdt.CalculateCrossPair(ethUsdt)
|
||||
if err != nil {
|
||||
t.Fatalf("ToEs failed: %v", err)
|
||||
}
|
||||
err = okbEth.ToElastic()
|
||||
if err != nil {
|
||||
t.Fatalf("ToEs failed: %v", err)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user