calc_utils.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. package arbitrage
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "github.com/shopspring/decimal"
  6. )
  7. type Simulation struct {
  8. AmountIn decimal.Decimal
  9. AmountInStr string `json:"AmountIn"`
  10. AmountOut0 decimal.Decimal
  11. AmountOut0Str string `json:"AmountOut0"`
  12. AmountOut1 decimal.Decimal
  13. AmountOut1Str string `json:"AmountOut1"`
  14. AmountOut2 decimal.Decimal
  15. AmountOut2Str string `json:"AmountOut2"`
  16. Profit decimal.Decimal
  17. ProfitStr string `json:"Profit"`
  18. }
  19. func (s *Simulation) ToJsonString() string {
  20. jsonBytes, _ := json.Marshal(s)
  21. return string(jsonBytes)
  22. }
  23. func SimulationLevel2Path(path *Path) {
  24. if path.Level != 2 {
  25. HistoryError(fmt.Sprintf("Level error. Need %v, but got %v", 2, path.Level))
  26. return
  27. }
  28. fm0 := path.FmList[0]
  29. fm1 := path.FmList[1]
  30. // fee0, fee1
  31. fee0 := decimal.NewFromInt(fm0.Fee)
  32. fee1 := decimal.NewFromInt(fm1.Fee)
  33. decimalNumber1 := decimal.NewFromInt(1)
  34. decimalNumber1e6 := decimal.NewFromInt(1e6)
  35. // F0 = 1 - fee0/1e6
  36. F0 := decimalNumber1.Sub(fee0.Div(decimalNumber1e6))
  37. // F1 = 1 - fee1/1e6
  38. F1 := decimalNumber1.Sub(fee1.Div(decimalNumber1e6))
  39. // B0, S0
  40. B0, _ := decimal.NewFromString(fm0.InReserve.String())
  41. S0, _ := decimal.NewFromString(fm0.OutReserve.String())
  42. // B1, S1
  43. B1, _ := decimal.NewFromString(fm1.InReserve.String())
  44. S1, _ := decimal.NewFromString(fm1.OutReserve.String())
  45. // if F0*F1*S0 + B1*F0 == 0
  46. partX := F0.Mul(F1).Mul(S0).Add(B1.Mul(F0))
  47. if partX.Equals(decimal.NewFromInt(0)) {
  48. HistoryError(fmt.Sprintf("Is error partX. F0=%v, F1=%v, S0=%v, B1=%v", F0, F1, S0, B1))
  49. return
  50. }
  51. // (B0 * B1 * F0 * F1 * S0 * S1) ** 0.5
  52. partB0 := Sqrt(B0.Mul(B1).Mul(F0).Mul(F1).Mul(S0).Mul(S1), 0)
  53. // B0 * B1 * F0 * F1 * S0 * S1 - B0 * B1
  54. partB := partB0.Sub(B0.Mul(B1))
  55. // best input number
  56. I := partB.Div(partX).Truncate(0)
  57. amountIn := I
  58. amountOut0 := CalcOutByIn(amountIn, B0, S0, fee0)
  59. amountOut1 := CalcOutByIn(amountOut0, B1, S1, fee1)
  60. profit := amountOut1.Sub(amountIn)
  61. path.Profit = profit
  62. path.Sim = Simulation{
  63. AmountIn: amountIn,
  64. AmountInStr: amountIn.String(),
  65. AmountOut0: amountOut0,
  66. AmountOut0Str: amountOut0.String(),
  67. AmountOut1: amountOut1,
  68. AmountOut1Str: amountOut1.String(),
  69. Profit: profit,
  70. ProfitStr: profit.String(),
  71. }
  72. }
  73. func SimulationLevel3Path(path *Path) {
  74. if path.Level != 3 {
  75. HistoryError(fmt.Sprintf("Level error. Need %v, but got %v", 3, path.Level))
  76. return
  77. }
  78. fm0 := path.FmList[0]
  79. fm1 := path.FmList[1]
  80. fm2 := path.FmList[2]
  81. // fee0, fee1
  82. fee0 := decimal.NewFromInt(fm0.Fee)
  83. fee1 := decimal.NewFromInt(fm1.Fee)
  84. fee2 := decimal.NewFromInt(fm2.Fee)
  85. decimalNumber1 := decimal.NewFromInt(1)
  86. decimalNumber1e6 := decimal.NewFromInt(1e6)
  87. // F0 = 1 - fee0/1e6
  88. F0 := decimalNumber1.Sub(fee0.Div(decimalNumber1e6))
  89. // F1 = 1 - fee1/1e6
  90. F1 := decimalNumber1.Sub(fee1.Div(decimalNumber1e6))
  91. // F2 = 1 - fee2 / 1e6
  92. F2 := decimalNumber1.Sub(fee2.Div(decimalNumber1e6))
  93. // B0, S0
  94. B0, _ := decimal.NewFromString(fm0.InReserve.String())
  95. S0, _ := decimal.NewFromString(fm0.OutReserve.String())
  96. // B1, S1
  97. B1, _ := decimal.NewFromString(fm1.InReserve.String())
  98. S1, _ := decimal.NewFromString(fm1.OutReserve.String())
  99. // B2, S2
  100. B2, _ := decimal.NewFromString(fm2.InReserve.String())
  101. S2, _ := decimal.NewFromString(fm2.OutReserve.String())
  102. // if (F0 * F1 * F2 * S0 * S1 + B2 * F0 * F1 * S0 + B1 * B2 * F0) == 0
  103. partX := F0.Mul(F1).Mul(F2).Mul(S0).Mul(S1).Add(B2.Mul(F0).Mul(F1).Mul(S0).Add(B1.Mul(B2).Mul(F0)))
  104. if partX.Equals(decimal.NewFromInt(0)) {
  105. HistoryError(fmt.Sprintf("Is error partX. F0=%v, F1=%v, F2=%v, S0=%v, S1=%v, B1=%v, B2=%v", F0, F1, F2, S0, S1, B1, B2))
  106. return
  107. }
  108. // (B0 * B1 * B2 * F0 * F1 * F2 * S0 * S1 * S2) ** 0.5
  109. partA0 := Sqrt(B0.Mul(B1).Mul(B2).Mul(S0).Mul(S1).Mul(S2).Mul(F0).Mul(F1).Mul(F2), 0)
  110. // B0 * B1 * B2
  111. partA1 := B0.Mul(B1).Mul(B2)
  112. // ((B0 * B1 * B2 * F0 * F1 * F2 * S0 * S1 * S2) ** 0.5 - B0 * B1 * B2) / F0 * F1 * F2 * S0 * S1 + B2 * F0 * F1 * S0 + B1 * B2 * F0
  113. amountIn := partA0.Sub(partA1).Div(partX).Truncate(0)
  114. //HistoryInfo(fmt.Sprintf("amountIn=%v", amountIn))
  115. decimalNumber2 := decimal.NewFromInt(2)
  116. amountOut0 := CalcOutByIn(amountIn, B0, S0, fee0).Sub(decimalNumber2)
  117. amountOut1 := CalcOutByIn(amountOut0, B1, S1, fee1).Sub(decimalNumber2)
  118. amountOut2 := CalcOutByIn(amountOut1, B2, S2, fee2).Sub(decimalNumber2)
  119. profit := amountOut2.Sub(amountIn)
  120. path.Profit = profit
  121. path.Sim = Simulation{
  122. AmountIn: amountIn,
  123. AmountInStr: amountIn.String(),
  124. AmountOut0: amountOut0,
  125. AmountOut0Str: amountOut0.String(),
  126. AmountOut1: amountOut1,
  127. AmountOut1Str: amountOut1.String(),
  128. AmountOut2: amountOut2,
  129. AmountOut2Str: amountOut2.String(),
  130. Profit: profit,
  131. ProfitStr: profit.String(),
  132. }
  133. }
  134. func CalcOutByIn(amountIn decimal.Decimal, reserveIn decimal.Decimal, reserveOut decimal.Decimal, fee decimal.Decimal) decimal.Decimal {
  135. if amountIn.LessThan(decimal.NewFromInt(1)) {
  136. return decimal.NewFromInt(0)
  137. }
  138. decimalNumber1e6 := decimal.NewFromInt(1e6)
  139. decimalNumber1e4 := decimal.NewFromInt(1e4)
  140. decimalNumber1e2 := decimal.NewFromInt(1e2)
  141. afterFee := decimalNumber1e6.Sub(fee).Div(decimalNumber1e2)
  142. amountInWithFee := amountIn.Mul(afterFee)
  143. // 分子
  144. numerator := amountInWithFee.Mul(reserveOut)
  145. // 分母
  146. denominator := reserveIn.Mul(decimalNumber1e4).Add(amountInWithFee)
  147. amountOut := numerator.Div(denominator).Sub(decimal.NewFromInt(1))
  148. return amountOut.Truncate(0)
  149. }
  150. // Sqrt 开平方
  151. func Sqrt(d decimal.Decimal, precision int32) decimal.Decimal {
  152. half := decimal.NewFromInt(2)
  153. guess := d.Div(half)
  154. tolerance := decimal.NewFromFloat(0.00000001)
  155. for {
  156. dGuess := d.Div(guess)
  157. diff := dGuess.Sub(guess).Abs()
  158. if diff.LessThan(tolerance) {
  159. break
  160. }
  161. guess = guess.Add(dGuess).Div(half)
  162. }
  163. return guess.Truncate(precision)
  164. }
  165. // Cbrt 开立方
  166. func Cbrt(d decimal.Decimal, precision int32) decimal.Decimal {
  167. two := decimal.NewFromInt(2)
  168. three := decimal.NewFromInt(3)
  169. guess := d.Div(two)
  170. tolerance := decimal.NewFromFloat(0.00000001)
  171. for {
  172. dGuess := d.Div(guess.Mul(guess))
  173. diff := dGuess.Sub(guess).Abs()
  174. if diff.LessThan(tolerance) {
  175. break
  176. }
  177. guess = guess.Mul(two).Add(dGuess).Div(three)
  178. }
  179. return guess.Truncate(precision)
  180. }