ccxt-go/exchange_precise.go
zhangkun9038@dingtalk.com 1a2ce7046a first add
2025-02-28 10:33:20 +08:00

484 lines
12 KiB
Go

package ccxt
import (
"fmt"
"math"
"math/big"
"strconv"
"strings"
)
type PreciseStruct struct {
Decimals interface{}
integer *big.Int
baseNumber int64
}
var Precise = &PreciseStruct{}
func NewPrecise(number2 interface{}, dec2 ...interface{}) *PreciseStruct {
var dec int
if len(dec2) > 0 {
dec = int(ParseInt(dec2[0]))
} else {
dec = math.MinInt32
}
number := fmt.Sprintf("%v", number2)
p := &PreciseStruct{
baseNumber: 10,
}
if dec == math.MinInt32 {
modified := 0
numberLowerCase := strings.ToLower(number)
if strings.Contains(numberLowerCase, "e") {
parts := strings.Split(numberLowerCase, "e")
number = parts[0]
modified, _ = strconv.Atoi(parts[1])
}
decimalIndex := strings.Index(number, ".")
var newDecimals int
if decimalIndex > -1 {
newDecimals = len(number) - decimalIndex - 1
} else {
newDecimals = 0
}
p.Decimals = newDecimals
integerString := strings.Replace(number, ".", "", -1)
p.integer = new(big.Int)
p.integer.SetString(integerString, 10)
p.Decimals = newDecimals - modified
} else {
p.integer = new(big.Int)
p.integer.SetString(number, 10)
p.Decimals = dec
}
return p
}
func (p *PreciseStruct) Mul(other *PreciseStruct) *PreciseStruct {
integer := new(big.Int).Mul(p.integer, other.integer)
decimals := p.Decimals.(int) + other.Decimals.(int)
return NewPrecise(integer.String(), decimals)
}
func (p *PreciseStruct) Div(other *PreciseStruct, precision2 ...interface{}) *PreciseStruct {
precision := int64(18)
if len(precision2) > 0 {
precision = ParseInt(precision2[0])
}
distance := precision - ParseInt(p.Decimals) + ParseInt(other.Decimals)
var numerator *big.Int
if distance == 0 {
numerator = p.integer
} else if distance < 0 {
exponent := new(big.Int).Exp(big.NewInt(p.baseNumber), big.NewInt(int64(-distance)), nil)
numerator = new(big.Int).Div(p.integer, exponent)
} else {
exponent := new(big.Int).Exp(big.NewInt(p.baseNumber), big.NewInt(int64(distance)), nil)
numerator = new(big.Int).Mul(p.integer, exponent)
}
result := new(big.Int).Div(numerator, other.integer)
return NewPrecise(result.String(), precision)
}
func (p *PreciseStruct) Add(other *PreciseStruct) *PreciseStruct {
if p.Decimals == other.Decimals {
integerResult := new(big.Int).Add(p.integer, other.integer)
return NewPrecise(integerResult.String(), p.Decimals.(int))
} else {
var smaller, bigger *PreciseStruct
if p.Decimals.(int) < other.Decimals.(int) {
smaller = p
bigger = other
} else {
smaller = other
bigger = p
}
exponent := bigger.Decimals.(int) - smaller.Decimals.(int)
normalized := new(big.Int).Mul(smaller.integer, new(big.Int).Exp(big.NewInt(p.baseNumber), big.NewInt(int64(exponent)), nil))
result := new(big.Int).Add(normalized, bigger.integer)
return NewPrecise(result.String(), bigger.Decimals.(int))
}
}
func (p *PreciseStruct) Mod(other *PreciseStruct) *PreciseStruct {
rationizerNumerator := int(math.Max(float64(-p.Decimals.(int)+other.Decimals.(int)), 0))
numerator := new(big.Int).Mul(p.integer, new(big.Int).Exp(big.NewInt(p.baseNumber), big.NewInt(int64(rationizerNumerator)), nil))
rationizerDenominator := int(math.Max(float64(-other.Decimals.(int)+p.Decimals.(int)), 0))
denominator := new(big.Int).Mul(other.integer, new(big.Int).Exp(big.NewInt(p.baseNumber), big.NewInt(int64(rationizerDenominator)), nil))
result := new(big.Int).Mod(numerator, denominator)
return NewPrecise(result.String(), rationizerDenominator+other.Decimals.(int))
}
func (p *PreciseStruct) Sub(other *PreciseStruct) *PreciseStruct {
negative := NewPrecise(new(big.Int).Neg(other.integer).String(), other.Decimals.(int))
return p.Add(negative)
}
func (p *PreciseStruct) Or(other *PreciseStruct) *PreciseStruct {
integer := new(big.Int).Or(p.integer, other.integer)
decimals := p.Decimals.(int) + other.Decimals.(int)
return NewPrecise(integer.String(), decimals)
}
func (p *PreciseStruct) Neg() *PreciseStruct {
return NewPrecise(new(big.Int).Neg(p.integer).String(), p.Decimals.(int))
}
func (p *PreciseStruct) Min(other *PreciseStruct) *PreciseStruct {
if p.Lt(other) {
return p
}
return other
}
func (p *PreciseStruct) Max(other *PreciseStruct) *PreciseStruct {
if p.Gt(other) {
return p
}
return other
}
func (p *PreciseStruct) Gt(other *PreciseStruct) bool {
sum := p.Sub(other)
return sum.integer.Cmp(big.NewInt(0)) > 0
}
func (p *PreciseStruct) Ge(other *PreciseStruct) bool {
sum := p.Sub(other)
return sum.integer.Cmp(big.NewInt(0)) >= 0
}
func (p *PreciseStruct) Lt(other *PreciseStruct) bool {
return other.Gt(p)
}
func (p *PreciseStruct) Le(other *PreciseStruct) bool {
return other.Ge(p)
}
func (p *PreciseStruct) Abs() *PreciseStruct {
var result *big.Int
if p.integer.Cmp(big.NewInt(0)) < 0 {
result = new(big.Int).Mul(p.integer, big.NewInt(-1))
} else {
result = p.integer
}
return NewPrecise(result.String(), p.Decimals.(int))
}
func (p *PreciseStruct) Reduce() *PreciseStruct {
str := p.integer.String()
start := len(str) - 1
if start == 0 {
if str == "0" {
p.Decimals = 0
}
return p
}
i := start
for ; i >= 0; i-- {
if str[i] != '0' {
break
}
}
difference := start - i
if difference == 0 {
return p
}
p.Decimals = int(ParseInt(p.Decimals)) - difference
p.integer = new(big.Int)
p.integer.SetString(str[:i+1], 10)
return p
}
func (p *PreciseStruct) Equals(other *PreciseStruct) bool {
p.Reduce()
other.Reduce()
return p.integer.Cmp(other.integer) == 0 && p.Decimals.(int) == other.Decimals.(int)
}
func (p *PreciseStruct) String() string {
p.Reduce()
sign := ""
var abs *big.Int
if p.integer.Cmp(big.NewInt(0)) < 0 {
sign = "-"
abs = new(big.Int).Mul(p.integer, big.NewInt(-1))
} else {
abs = p.integer
}
absParsed := abs.String()
padSize := p.Decimals.(int)
if padSize < 0 {
padSize = 0
}
integerArray := strings.Split(fmt.Sprintf("%0*s", padSize, absParsed), "")
index := len(integerArray) - p.Decimals.(int)
item := ""
if index == 0 {
item = "0."
} else if p.Decimals.(int) < 0 {
item = strings.Repeat("0", -p.Decimals.(int))
} else if p.Decimals.(int) == 0 {
item = ""
} else {
item = "."
}
arrayIndex := index
if arrayIndex > len(integerArray) {
arrayIndex = len(integerArray)
}
integerArray = append(integerArray[:arrayIndex], append([]string{item}, integerArray[arrayIndex:]...)...)
return sign + strings.Join(integerArray, "")
}
func StringMul(string1, string2 interface{}) string {
if string1 == nil || string2 == nil {
return ""
}
return NewPrecise(string1.(string)).Mul(NewPrecise(string2.(string))).String()
}
func StringDiv(string1, string2 interface{}, precision ...interface{}) string {
if string1 == nil || string2 == nil {
return ""
}
string2Precise := NewPrecise(string2.(string))
if string2Precise.integer.Cmp(big.NewInt(0)) == 0 {
return ""
}
stringDiv := NewPrecise(string1.(string)).Div(string2Precise, precision...)
return stringDiv.String()
}
func StringSub(string1, string2 interface{}) string {
if string1 == nil || string2 == nil {
return ""
}
return NewPrecise(string1.(string)).Sub(NewPrecise(string2.(string))).String()
}
// func (this *PreciseStruct) stringSub(string1, string2 interface{}) string {
// return StringSub(string1, string2)
// }
func StringAdd(string1, string2 interface{}) string {
if string1 == nil && string2 == nil {
return ""
}
if string1 == nil {
return string2.(string)
}
if string2 == nil {
return string1.(string)
}
return NewPrecise(string1.(string)).Add(NewPrecise(string2.(string))).String()
}
func StringOr(string1, string2 interface{}) string {
if string1 == nil || string2 == nil {
return ""
}
return NewPrecise(string1.(string)).Or(NewPrecise(string2.(string))).String()
}
func StringGt(a, b interface{}) bool {
if a == nil || b == nil {
return false
}
return NewPrecise(a.(string)).Gt(NewPrecise(b.(string)))
}
func StringEq(a, b interface{}) bool {
if a == nil || b == nil {
return false
}
return NewPrecise(a.(string)).Equals(NewPrecise(b.(string)))
}
func StringMax(a, b interface{}) string {
if a == nil || b == nil {
return ""
}
return NewPrecise(a.(string)).Max(NewPrecise(b.(string))).String()
}
func StringEquals(a, b interface{}) bool {
if a == nil || b == nil {
return false
}
return NewPrecise(a.(string)).Equals(NewPrecise(b.(string)))
}
func StringMin(string1, string2 interface{}) string {
if string1 == nil || string2 == nil {
return ""
}
return NewPrecise(string1.(string)).Min(NewPrecise(string2.(string))).String()
}
func StringLt(a, b interface{}) bool {
if a == nil || b == nil {
return false
}
return NewPrecise(a.(string)).Lt(NewPrecise(b.(string)))
}
func StringAbs(a interface{}) string {
if a == nil {
return ""
}
return NewPrecise(a.(string)).Abs().String()
}
func StringNeg(a interface{}) string {
if a == nil {
return ""
}
return NewPrecise(a.(string)).Neg().String()
}
func StringLe(a, b interface{}) bool {
if a == nil || b == nil {
return false
}
return NewPrecise(a.(string)).Le(NewPrecise(b.(string)))
}
func StringGe(a, b interface{}) bool {
if a == nil || b == nil {
return false
}
return NewPrecise(a.(string)).Ge(NewPrecise(b.(string)))
}
func StringMod(a, b interface{}) string {
if a == nil || b == nil {
return ""
}
return NewPrecise(a.(string)).Mod(NewPrecise(b.(string))).String()
}
func (p *PreciseStruct) ToString() string {
p.Reduce() // Call the reduce method if any
// Determine the sign and absolute value
var sign string
abs := new(big.Int)
if p.integer.Sign() < 0 {
sign = "-"
abs.Neg(p.integer) // Negate the integer to get the absolute value
} else {
sign = ""
abs.Set(p.integer) // Copy the positive value of the integer
}
intPDecimals := ParseInt(p.Decimals)
// Convert the absolute value to a string
// integerStr := fmt.Sprintf("%0*d", intPDecimals+ParseInt(len(abs.String())), abs)
// integerArray := strings.Split(integerStr, "")
// // Calculate the index to insert the decimal point
var item string
absParsed := abs.String()
padSize := 0
if intPDecimals > 0 {
padSize = int(intPDecimals)
}
absParsed = fmt.Sprintf("%0*s", len(absParsed)+padSize, absParsed)
integerArray := strings.Split(absParsed, "")
// index := len(integerArray) - intPDecimals
index := ParseInt(len(integerArray)) - intPDecimals
// Handle cases based on the value of decimals
if index == 0 {
item = "0."
} else if intPDecimals < 0 {
item = strings.Repeat("0", -int(intPDecimals))
} else if intPDecimals == 0 {
item = ""
} else {
item = "."
}
arrayIndex := index
arrayLength := ParseInt(len(integerArray))
if index > arrayLength {
arrayIndex = arrayLength
}
integerArray = append(integerArray[:arrayIndex], append([]string{item}, integerArray[arrayIndex:]...)...)
return sign + strings.Join(integerArray, "")
}
// wrappers
func (e *PreciseStruct) StringMul(string1, string2 interface{}) string {
return StringMul(string1, string2)
}
func (e *PreciseStruct) StringDiv(string1, string2 interface{}, precision ...interface{}) string {
return StringDiv(string1, string2, precision...)
}
func (e *PreciseStruct) StringSub(string1, string2 interface{}) string {
return StringSub(string1, string2)
}
func (e *PreciseStruct) StringAdd(string1, string2 interface{}) string {
return StringAdd(string1, string2)
}
func (e *PreciseStruct) StringOr(string1, string2 interface{}) string {
return StringOr(string1, string2)
}
func (e *PreciseStruct) StringGt(a, b interface{}) bool {
return StringGt(a, b)
}
func (e *PreciseStruct) StringEq(a, b interface{}) bool {
return StringEq(a, b)
}
func (e *PreciseStruct) StringMax(a, b interface{}) string {
return StringMax(a, b)
}
func (e *PreciseStruct) StringEquals(a, b interface{}) bool {
return StringEquals(a, b)
}
func (e *PreciseStruct) StringMin(string1, string2 interface{}) string {
return StringMin(string1, string2)
}
func (e *PreciseStruct) StringLt(a, b interface{}) bool {
return StringLt(a, b)
}
func (e *PreciseStruct) StringAbs(a interface{}) string {
return StringAbs(a)
}
func (e *PreciseStruct) StringNeg(a interface{}) string {
return StringNeg(a)
}
func (e *PreciseStruct) StringLe(a, b interface{}) bool {
return StringLe(a, b)
}
func (e *PreciseStruct) StringGe(a, b interface{}) bool {
return StringGe(a, b)
}
func (e *PreciseStruct) StringMod(a, b interface{}) string {
return StringMod(a, b)
}