@catalyst-team/poly-sdk 0.3.0 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (317) hide show
  1. package/README.md +133 -1
  2. package/README.zh-CN.md +2 -0
  3. package/dist/scripts/dip-arb/auto-trade.d.ts +20 -0
  4. package/dist/scripts/dip-arb/auto-trade.d.ts.map +1 -0
  5. package/dist/scripts/dip-arb/auto-trade.js +373 -0
  6. package/dist/scripts/dip-arb/auto-trade.js.map +1 -0
  7. package/dist/scripts/dip-arb/example-basic.d.ts +30 -0
  8. package/dist/scripts/dip-arb/example-basic.d.ts.map +1 -0
  9. package/dist/scripts/dip-arb/example-basic.js +222 -0
  10. package/dist/scripts/dip-arb/example-basic.js.map +1 -0
  11. package/dist/scripts/dip-arb/redeem-positions.d.ts +11 -0
  12. package/dist/scripts/dip-arb/redeem-positions.d.ts.map +1 -0
  13. package/dist/scripts/dip-arb/redeem-positions.js +201 -0
  14. package/dist/scripts/dip-arb/redeem-positions.js.map +1 -0
  15. package/dist/scripts/dip-arb/scan-markets.d.ts +6 -0
  16. package/dist/scripts/dip-arb/scan-markets.d.ts.map +1 -0
  17. package/dist/scripts/dip-arb/scan-markets.js +73 -0
  18. package/dist/scripts/dip-arb/scan-markets.js.map +1 -0
  19. package/dist/src/__tests__/integration/arbitrage-service.integration.test.d.ts.map +1 -0
  20. package/dist/src/__tests__/integration/arbitrage-service.integration.test.js.map +1 -0
  21. package/dist/src/__tests__/integration/bridge-client.integration.test.d.ts.map +1 -0
  22. package/dist/src/__tests__/integration/bridge-client.integration.test.js.map +1 -0
  23. package/dist/src/__tests__/integration/ctf-client.integration.test.d.ts.map +1 -0
  24. package/dist/src/__tests__/integration/ctf-client.integration.test.js.map +1 -0
  25. package/dist/src/__tests__/integration/data-api.integration.test.d.ts.map +1 -0
  26. package/dist/{__tests__ → src/__tests__}/integration/data-api.integration.test.js +21 -18
  27. package/dist/src/__tests__/integration/data-api.integration.test.js.map +1 -0
  28. package/dist/src/__tests__/integration/gamma-api.integration.test.d.ts.map +1 -0
  29. package/dist/src/__tests__/integration/gamma-api.integration.test.js.map +1 -0
  30. package/dist/src/__tests__/integration/market-service.integration.test.d.ts.map +1 -0
  31. package/dist/{__tests__ → src/__tests__}/integration/market-service.integration.test.js +7 -0
  32. package/dist/src/__tests__/integration/market-service.integration.test.js.map +1 -0
  33. package/dist/src/__tests__/integration/realtime-service-v2.integration.test.d.ts.map +1 -0
  34. package/dist/src/__tests__/integration/realtime-service-v2.integration.test.js.map +1 -0
  35. package/dist/src/__tests__/integration/trading-service.integration.test.d.ts.map +1 -0
  36. package/dist/src/__tests__/integration/trading-service.integration.test.js.map +1 -0
  37. package/dist/src/__tests__/test-utils.d.ts.map +1 -0
  38. package/dist/src/__tests__/test-utils.js.map +1 -0
  39. package/dist/src/catalyst/catalyst-query-service.d.ts +109 -0
  40. package/dist/src/catalyst/catalyst-query-service.d.ts.map +1 -0
  41. package/dist/src/catalyst/catalyst-query-service.js +141 -0
  42. package/dist/src/catalyst/catalyst-query-service.js.map +1 -0
  43. package/dist/src/catalyst/catalyst-realtime-service.d.ts +40 -0
  44. package/dist/src/catalyst/catalyst-realtime-service.d.ts.map +1 -0
  45. package/dist/src/catalyst/catalyst-realtime-service.js +125 -0
  46. package/dist/src/catalyst/catalyst-realtime-service.js.map +1 -0
  47. package/dist/src/catalyst/index.d.ts +4 -0
  48. package/dist/src/catalyst/index.d.ts.map +1 -0
  49. package/dist/src/catalyst/index.js +4 -0
  50. package/dist/src/catalyst/index.js.map +1 -0
  51. package/dist/src/catalyst/types.d.ts +178 -0
  52. package/dist/src/catalyst/types.d.ts.map +1 -0
  53. package/dist/src/catalyst/types.js +2 -0
  54. package/dist/src/catalyst/types.js.map +1 -0
  55. package/dist/src/clients/bridge-client.d.ts.map +1 -0
  56. package/dist/src/clients/bridge-client.js.map +1 -0
  57. package/dist/{clients → src/clients}/ctf-client.d.ts +6 -4
  58. package/dist/src/clients/ctf-client.d.ts.map +1 -0
  59. package/dist/src/clients/ctf-client.js.map +1 -0
  60. package/dist/{clients → src/clients}/data-api.d.ts +94 -20
  61. package/dist/src/clients/data-api.d.ts.map +1 -0
  62. package/dist/{clients → src/clients}/data-api.js +119 -52
  63. package/dist/src/clients/data-api.js.map +1 -0
  64. package/dist/{clients → src/clients}/gamma-api.d.ts +74 -0
  65. package/dist/src/clients/gamma-api.d.ts.map +1 -0
  66. package/dist/{clients → src/clients}/gamma-api.js +7 -0
  67. package/dist/src/clients/gamma-api.js.map +1 -0
  68. package/dist/src/clients/subgraph.d.ts.map +1 -0
  69. package/dist/src/clients/subgraph.js.map +1 -0
  70. package/dist/src/core/cache-adapter-bridge.d.ts.map +1 -0
  71. package/dist/src/core/cache-adapter-bridge.js.map +1 -0
  72. package/dist/{core → src/core}/cache.d.ts +2 -0
  73. package/dist/src/core/cache.d.ts.map +1 -0
  74. package/dist/{core → src/core}/cache.js +4 -0
  75. package/dist/src/core/cache.js.map +1 -0
  76. package/dist/src/core/errors.d.ts.map +1 -0
  77. package/dist/src/core/errors.js.map +1 -0
  78. package/dist/{core → src/core}/rate-limiter.d.ts +2 -1
  79. package/dist/src/core/rate-limiter.d.ts.map +1 -0
  80. package/dist/{core → src/core}/rate-limiter.js +7 -0
  81. package/dist/src/core/rate-limiter.js.map +1 -0
  82. package/dist/{core → src/core}/types.d.ts +105 -1
  83. package/dist/src/core/types.d.ts.map +1 -0
  84. package/dist/src/core/types.js +49 -0
  85. package/dist/src/core/types.js.map +1 -0
  86. package/dist/src/core/types.test.d.ts.map +1 -0
  87. package/dist/src/core/types.test.js.map +1 -0
  88. package/dist/src/core/unified-cache.d.ts.map +1 -0
  89. package/dist/src/core/unified-cache.js.map +1 -0
  90. package/dist/{index.d.ts → src/index.d.ts} +24 -5
  91. package/dist/src/index.d.ts.map +1 -0
  92. package/dist/{index.js → src/index.js} +38 -4
  93. package/dist/src/index.js.map +1 -0
  94. package/dist/src/insider-scan/index.d.ts +3 -0
  95. package/dist/src/insider-scan/index.d.ts.map +1 -0
  96. package/dist/src/insider-scan/index.js +3 -0
  97. package/dist/src/insider-scan/index.js.map +1 -0
  98. package/dist/src/insider-scan/insider-scan-service.d.ts +63 -0
  99. package/dist/src/insider-scan/insider-scan-service.d.ts.map +1 -0
  100. package/dist/src/insider-scan/insider-scan-service.js +153 -0
  101. package/dist/src/insider-scan/insider-scan-service.js.map +1 -0
  102. package/dist/src/insider-scan/types.d.ts +205 -0
  103. package/dist/src/insider-scan/types.d.ts.map +1 -0
  104. package/dist/src/insider-scan/types.js +7 -0
  105. package/dist/src/insider-scan/types.js.map +1 -0
  106. package/dist/src/services/arbitrage-service.d.ts.map +1 -0
  107. package/dist/{services → src/services}/arbitrage-service.js +14 -4
  108. package/dist/src/services/arbitrage-service.js.map +1 -0
  109. package/dist/src/services/authorization-service.d.ts.map +1 -0
  110. package/dist/src/services/authorization-service.js.map +1 -0
  111. package/dist/src/services/binance-service.d.ts +154 -0
  112. package/dist/src/services/binance-service.d.ts.map +1 -0
  113. package/dist/src/services/binance-service.js +266 -0
  114. package/dist/src/services/binance-service.js.map +1 -0
  115. package/dist/src/services/dip-arb-service.d.ts +245 -0
  116. package/dist/src/services/dip-arb-service.d.ts.map +1 -0
  117. package/dist/src/services/dip-arb-service.js +1865 -0
  118. package/dist/src/services/dip-arb-service.js.map +1 -0
  119. package/dist/src/services/dip-arb-types.d.ts +553 -0
  120. package/dist/src/services/dip-arb-types.d.ts.map +1 -0
  121. package/dist/src/services/dip-arb-types.js +164 -0
  122. package/dist/src/services/dip-arb-types.js.map +1 -0
  123. package/dist/src/services/market-service.d.ts +431 -0
  124. package/dist/src/services/market-service.d.ts.map +1 -0
  125. package/dist/{services → src/services}/market-service.js +501 -17
  126. package/dist/src/services/market-service.js.map +1 -0
  127. package/dist/{services → src/services}/onchain-service.d.ts +10 -2
  128. package/dist/src/services/onchain-service.d.ts.map +1 -0
  129. package/dist/{services → src/services}/onchain-service.js +8 -0
  130. package/dist/src/services/onchain-service.js.map +1 -0
  131. package/dist/{services → src/services}/realtime-service-v2.d.ts +6 -0
  132. package/dist/src/services/realtime-service-v2.d.ts.map +1 -0
  133. package/dist/{services → src/services}/realtime-service-v2.js +44 -8
  134. package/dist/src/services/realtime-service-v2.js.map +1 -0
  135. package/dist/src/services/smart-money-service.d.ts +769 -0
  136. package/dist/src/services/smart-money-service.d.ts.map +1 -0
  137. package/dist/src/services/smart-money-service.js +1448 -0
  138. package/dist/src/services/smart-money-service.js.map +1 -0
  139. package/dist/src/services/swap-service.d.ts.map +1 -0
  140. package/dist/src/services/swap-service.js.map +1 -0
  141. package/dist/{services → src/services}/trading-service.d.ts +26 -0
  142. package/dist/src/services/trading-service.d.ts.map +1 -0
  143. package/dist/{services → src/services}/trading-service.js +72 -1
  144. package/dist/src/services/trading-service.js.map +1 -0
  145. package/dist/{services → src/services}/wallet-service.d.ts +81 -4
  146. package/dist/src/services/wallet-service.d.ts.map +1 -0
  147. package/dist/{services → src/services}/wallet-service.js +126 -8
  148. package/dist/src/services/wallet-service.js.map +1 -0
  149. package/dist/src/signal/index.d.ts +8 -0
  150. package/dist/src/signal/index.d.ts.map +1 -0
  151. package/dist/src/signal/index.js +7 -0
  152. package/dist/src/signal/index.js.map +1 -0
  153. package/dist/src/signal/signal-service.d.ts +89 -0
  154. package/dist/src/signal/signal-service.d.ts.map +1 -0
  155. package/dist/src/signal/signal-service.js +226 -0
  156. package/dist/src/signal/signal-service.js.map +1 -0
  157. package/dist/src/signal/types.d.ts +280 -0
  158. package/dist/src/signal/types.d.ts.map +1 -0
  159. package/dist/src/signal/types.js +7 -0
  160. package/dist/src/signal/types.js.map +1 -0
  161. package/dist/src/utils/price-utils.d.ts.map +1 -0
  162. package/dist/src/utils/price-utils.js.map +1 -0
  163. package/dist/src/utils/price-utils.test.d.ts.map +1 -0
  164. package/dist/src/utils/price-utils.test.js.map +1 -0
  165. package/dist/src/wallet-report/index.d.ts +3 -0
  166. package/dist/src/wallet-report/index.d.ts.map +1 -0
  167. package/dist/src/wallet-report/index.js +3 -0
  168. package/dist/src/wallet-report/index.js.map +1 -0
  169. package/dist/src/wallet-report/types.d.ts +187 -0
  170. package/dist/src/wallet-report/types.d.ts.map +1 -0
  171. package/dist/src/wallet-report/types.js +7 -0
  172. package/dist/src/wallet-report/types.js.map +1 -0
  173. package/dist/src/wallet-report/wallet-report-service.d.ts +91 -0
  174. package/dist/src/wallet-report/wallet-report-service.d.ts.map +1 -0
  175. package/dist/src/wallet-report/wallet-report-service.js +208 -0
  176. package/dist/src/wallet-report/wallet-report-service.js.map +1 -0
  177. package/dist/src/wallets/hot-wallet-service.d.ts +162 -0
  178. package/dist/src/wallets/hot-wallet-service.d.ts.map +1 -0
  179. package/dist/src/wallets/hot-wallet-service.js +251 -0
  180. package/dist/src/wallets/hot-wallet-service.js.map +1 -0
  181. package/dist/src/wallets/index.d.ts +15 -0
  182. package/dist/src/wallets/index.d.ts.map +1 -0
  183. package/dist/src/wallets/index.js +26 -0
  184. package/dist/src/wallets/index.js.map +1 -0
  185. package/package.json +7 -7
  186. package/dist/__tests__/clob-api.test.d.ts +0 -5
  187. package/dist/__tests__/clob-api.test.d.ts.map +0 -1
  188. package/dist/__tests__/clob-api.test.js +0 -240
  189. package/dist/__tests__/clob-api.test.js.map +0 -1
  190. package/dist/__tests__/integration/arbitrage-service.integration.test.d.ts.map +0 -1
  191. package/dist/__tests__/integration/arbitrage-service.integration.test.js.map +0 -1
  192. package/dist/__tests__/integration/bridge-client.integration.test.d.ts.map +0 -1
  193. package/dist/__tests__/integration/bridge-client.integration.test.js.map +0 -1
  194. package/dist/__tests__/integration/clob-api.integration.test.d.ts +0 -13
  195. package/dist/__tests__/integration/clob-api.integration.test.d.ts.map +0 -1
  196. package/dist/__tests__/integration/clob-api.integration.test.js +0 -170
  197. package/dist/__tests__/integration/clob-api.integration.test.js.map +0 -1
  198. package/dist/__tests__/integration/ctf-client.integration.test.d.ts.map +0 -1
  199. package/dist/__tests__/integration/ctf-client.integration.test.js.map +0 -1
  200. package/dist/__tests__/integration/data-api.integration.test.d.ts.map +0 -1
  201. package/dist/__tests__/integration/data-api.integration.test.js.map +0 -1
  202. package/dist/__tests__/integration/gamma-api.integration.test.d.ts.map +0 -1
  203. package/dist/__tests__/integration/gamma-api.integration.test.js.map +0 -1
  204. package/dist/__tests__/integration/market-service.integration.test.d.ts.map +0 -1
  205. package/dist/__tests__/integration/market-service.integration.test.js.map +0 -1
  206. package/dist/__tests__/integration/realtime-service-v2.integration.test.d.ts.map +0 -1
  207. package/dist/__tests__/integration/realtime-service-v2.integration.test.js.map +0 -1
  208. package/dist/__tests__/integration/trading-service.integration.test.d.ts.map +0 -1
  209. package/dist/__tests__/integration/trading-service.integration.test.js.map +0 -1
  210. package/dist/__tests__/test-utils.d.ts.map +0 -1
  211. package/dist/__tests__/test-utils.js.map +0 -1
  212. package/dist/clients/bridge-client.d.ts.map +0 -1
  213. package/dist/clients/bridge-client.js.map +0 -1
  214. package/dist/clients/clob-api.d.ts +0 -391
  215. package/dist/clients/clob-api.d.ts.map +0 -1
  216. package/dist/clients/clob-api.js +0 -448
  217. package/dist/clients/clob-api.js.map +0 -1
  218. package/dist/clients/ctf-client.d.ts.map +0 -1
  219. package/dist/clients/ctf-client.js.map +0 -1
  220. package/dist/clients/data-api.d.ts.map +0 -1
  221. package/dist/clients/data-api.js.map +0 -1
  222. package/dist/clients/gamma-api.d.ts.map +0 -1
  223. package/dist/clients/gamma-api.js.map +0 -1
  224. package/dist/clients/subgraph.d.ts.map +0 -1
  225. package/dist/clients/subgraph.js.map +0 -1
  226. package/dist/clients/trading-client.d.ts +0 -252
  227. package/dist/clients/trading-client.d.ts.map +0 -1
  228. package/dist/clients/trading-client.js +0 -543
  229. package/dist/clients/trading-client.js.map +0 -1
  230. package/dist/clients/websocket-manager.d.ts +0 -103
  231. package/dist/clients/websocket-manager.d.ts.map +0 -1
  232. package/dist/clients/websocket-manager.js +0 -200
  233. package/dist/clients/websocket-manager.js.map +0 -1
  234. package/dist/core/cache-adapter-bridge.d.ts.map +0 -1
  235. package/dist/core/cache-adapter-bridge.js.map +0 -1
  236. package/dist/core/cache.d.ts.map +0 -1
  237. package/dist/core/cache.js.map +0 -1
  238. package/dist/core/errors.d.ts.map +0 -1
  239. package/dist/core/errors.js.map +0 -1
  240. package/dist/core/rate-limiter.d.ts.map +0 -1
  241. package/dist/core/rate-limiter.js.map +0 -1
  242. package/dist/core/types.d.ts.map +0 -1
  243. package/dist/core/types.js +0 -19
  244. package/dist/core/types.js.map +0 -1
  245. package/dist/core/types.test.d.ts.map +0 -1
  246. package/dist/core/types.test.js.map +0 -1
  247. package/dist/core/unified-cache.d.ts.map +0 -1
  248. package/dist/core/unified-cache.js.map +0 -1
  249. package/dist/index.d.ts.map +0 -1
  250. package/dist/index.js.map +0 -1
  251. package/dist/services/arbitrage-service.d.ts.map +0 -1
  252. package/dist/services/arbitrage-service.js.map +0 -1
  253. package/dist/services/authorization-service.d.ts.map +0 -1
  254. package/dist/services/authorization-service.js.map +0 -1
  255. package/dist/services/market-service.d.ts +0 -208
  256. package/dist/services/market-service.d.ts.map +0 -1
  257. package/dist/services/market-service.js.map +0 -1
  258. package/dist/services/onchain-service.d.ts.map +0 -1
  259. package/dist/services/onchain-service.js.map +0 -1
  260. package/dist/services/realtime-service-v2.d.ts.map +0 -1
  261. package/dist/services/realtime-service-v2.js.map +0 -1
  262. package/dist/services/realtime-service.d.ts +0 -82
  263. package/dist/services/realtime-service.d.ts.map +0 -1
  264. package/dist/services/realtime-service.js +0 -182
  265. package/dist/services/realtime-service.js.map +0 -1
  266. package/dist/services/smart-money-service.d.ts +0 -196
  267. package/dist/services/smart-money-service.d.ts.map +0 -1
  268. package/dist/services/smart-money-service.js +0 -358
  269. package/dist/services/smart-money-service.js.map +0 -1
  270. package/dist/services/swap-service.d.ts.map +0 -1
  271. package/dist/services/swap-service.js.map +0 -1
  272. package/dist/services/trading-service.d.ts.map +0 -1
  273. package/dist/services/trading-service.js.map +0 -1
  274. package/dist/services/wallet-service.d.ts.map +0 -1
  275. package/dist/services/wallet-service.js.map +0 -1
  276. package/dist/utils/price-utils.d.ts.map +0 -1
  277. package/dist/utils/price-utils.js.map +0 -1
  278. package/dist/utils/price-utils.test.d.ts.map +0 -1
  279. package/dist/utils/price-utils.test.js.map +0 -1
  280. /package/dist/{__tests__ → src/__tests__}/integration/arbitrage-service.integration.test.d.ts +0 -0
  281. /package/dist/{__tests__ → src/__tests__}/integration/arbitrage-service.integration.test.js +0 -0
  282. /package/dist/{__tests__ → src/__tests__}/integration/bridge-client.integration.test.d.ts +0 -0
  283. /package/dist/{__tests__ → src/__tests__}/integration/bridge-client.integration.test.js +0 -0
  284. /package/dist/{__tests__ → src/__tests__}/integration/ctf-client.integration.test.d.ts +0 -0
  285. /package/dist/{__tests__ → src/__tests__}/integration/ctf-client.integration.test.js +0 -0
  286. /package/dist/{__tests__ → src/__tests__}/integration/data-api.integration.test.d.ts +0 -0
  287. /package/dist/{__tests__ → src/__tests__}/integration/gamma-api.integration.test.d.ts +0 -0
  288. /package/dist/{__tests__ → src/__tests__}/integration/gamma-api.integration.test.js +0 -0
  289. /package/dist/{__tests__ → src/__tests__}/integration/market-service.integration.test.d.ts +0 -0
  290. /package/dist/{__tests__ → src/__tests__}/integration/realtime-service-v2.integration.test.d.ts +0 -0
  291. /package/dist/{__tests__ → src/__tests__}/integration/realtime-service-v2.integration.test.js +0 -0
  292. /package/dist/{__tests__ → src/__tests__}/integration/trading-service.integration.test.d.ts +0 -0
  293. /package/dist/{__tests__ → src/__tests__}/integration/trading-service.integration.test.js +0 -0
  294. /package/dist/{__tests__ → src/__tests__}/test-utils.d.ts +0 -0
  295. /package/dist/{__tests__ → src/__tests__}/test-utils.js +0 -0
  296. /package/dist/{clients → src/clients}/bridge-client.d.ts +0 -0
  297. /package/dist/{clients → src/clients}/bridge-client.js +0 -0
  298. /package/dist/{clients → src/clients}/ctf-client.js +0 -0
  299. /package/dist/{clients → src/clients}/subgraph.d.ts +0 -0
  300. /package/dist/{clients → src/clients}/subgraph.js +0 -0
  301. /package/dist/{core → src/core}/cache-adapter-bridge.d.ts +0 -0
  302. /package/dist/{core → src/core}/cache-adapter-bridge.js +0 -0
  303. /package/dist/{core → src/core}/errors.d.ts +0 -0
  304. /package/dist/{core → src/core}/errors.js +0 -0
  305. /package/dist/{core → src/core}/types.test.d.ts +0 -0
  306. /package/dist/{core → src/core}/types.test.js +0 -0
  307. /package/dist/{core → src/core}/unified-cache.d.ts +0 -0
  308. /package/dist/{core → src/core}/unified-cache.js +0 -0
  309. /package/dist/{services → src/services}/arbitrage-service.d.ts +0 -0
  310. /package/dist/{services → src/services}/authorization-service.d.ts +0 -0
  311. /package/dist/{services → src/services}/authorization-service.js +0 -0
  312. /package/dist/{services → src/services}/swap-service.d.ts +0 -0
  313. /package/dist/{services → src/services}/swap-service.js +0 -0
  314. /package/dist/{utils → src/utils}/price-utils.d.ts +0 -0
  315. /package/dist/{utils → src/utils}/price-utils.js +0 -0
  316. /package/dist/{utils → src/utils}/price-utils.test.d.ts +0 -0
  317. /package/dist/{utils → src/utils}/price-utils.test.js +0 -0
@@ -17,6 +17,30 @@ import { PolymarketError, ErrorCode } from '../core/errors.js';
17
17
  const CLOB_HOST = 'https://clob.polymarket.com';
18
18
  // Chain IDs
19
19
  export const POLYGON_MAINNET = 137;
20
+ /**
21
+ * Normalize timestamp to milliseconds.
22
+ * Polymarket API sometimes returns timestamps in seconds.
23
+ * Timestamps < 1e12 (year ~2001 in ms) are assumed to be in seconds.
24
+ */
25
+ function normalizeTimestamp(ts) {
26
+ return ts < 1e12 ? ts * 1000 : ts;
27
+ }
28
+ // Mapping from underlying asset to Binance symbol
29
+ const UNDERLYING_TO_SYMBOL = {
30
+ BTC: 'BTCUSDT',
31
+ ETH: 'ETHUSDT',
32
+ SOL: 'SOLUSDT',
33
+ };
34
+ // Map from KLineInterval to BinanceInterval (Binance doesn't support 30s or 12h)
35
+ const KLINE_TO_BINANCE_INTERVAL = {
36
+ '1m': '1m',
37
+ '5m': '5m',
38
+ '15m': '15m',
39
+ '30m': '30m',
40
+ '1h': '1h',
41
+ '4h': '4h',
42
+ '1d': '1d',
43
+ };
20
44
  // ============================================================================
21
45
  // MarketService Implementation
22
46
  // ============================================================================
@@ -26,14 +50,16 @@ export class MarketService {
26
50
  rateLimiter;
27
51
  cache;
28
52
  config;
53
+ binanceService;
29
54
  clobClient = null;
30
55
  initialized = false;
31
- constructor(gammaApi, dataApi, rateLimiter, cache, config) {
56
+ constructor(gammaApi, dataApi, rateLimiter, cache, config, binanceService) {
32
57
  this.gammaApi = gammaApi;
33
58
  this.dataApi = dataApi;
34
59
  this.rateLimiter = rateLimiter;
35
60
  this.cache = cache;
36
61
  this.config = config;
62
+ this.binanceService = binanceService;
37
63
  }
38
64
  // ============================================================================
39
65
  // Initialization
@@ -65,11 +91,81 @@ export class MarketService {
65
91
  return this.cache.getOrSet(cacheKey, CACHE_TTL.MARKET_INFO, async () => {
66
92
  const client = await this.ensureInitialized();
67
93
  return this.rateLimiter.execute(ApiType.CLOB_API, async () => {
68
- const market = await client.getMarket(conditionId);
69
- return this.normalizeClobMarket(market);
94
+ try {
95
+ const market = await client.getMarket(conditionId);
96
+ if (!market || !market.tokens) {
97
+ return null;
98
+ }
99
+ return this.normalizeClobMarket(market);
100
+ }
101
+ catch (error) {
102
+ // Handle 404 "market not found" gracefully
103
+ if (error && typeof error === 'object' && 'status' in error && error.status === 404) {
104
+ return null;
105
+ }
106
+ throw error;
107
+ }
70
108
  });
71
109
  });
72
110
  }
111
+ /**
112
+ * Resolve market tokens from CLOB API
113
+ *
114
+ * This method fetches the actual token IDs from the CLOB API,
115
+ * which are different from the calculated positionIds in standard CTF.
116
+ *
117
+ * ## Why This Method Exists
118
+ *
119
+ * Polymarket CLOB markets use custom ERC-1155 token IDs that are different
120
+ * from the standard CTF calculated positionIds:
121
+ *
122
+ * ```
123
+ * Standard CTF: positionId = keccak256(USDC + keccak256(0x0 + conditionId + indexSet))
124
+ * Polymarket: tokenId = custom value from CLOB API (e.g., "25064375110792...")
125
+ * ```
126
+ *
127
+ * This method provides the actual tokenIds needed for CTF operations
128
+ * (split, merge, redeem) on Polymarket markets.
129
+ *
130
+ * ## Usage with CTFClient
131
+ *
132
+ * Since CTFClient uses legacy `yesTokenId`/`noTokenId` naming,
133
+ * you need to convert when calling CTF methods:
134
+ *
135
+ * ```typescript
136
+ * const resolved = await sdk.markets.resolveMarketTokens(conditionId);
137
+ * if (resolved) {
138
+ * const tokenIds = {
139
+ * yesTokenId: resolved.primaryTokenId,
140
+ * noTokenId: resolved.secondaryTokenId,
141
+ * };
142
+ * await ctfClient.redeemByTokenIds(conditionId, tokenIds);
143
+ * }
144
+ * ```
145
+ *
146
+ * @param conditionId - Market condition ID (0x...)
147
+ * @returns Resolved token IDs with outcome names, or null if not found
148
+ */
149
+ async resolveMarketTokens(conditionId) {
150
+ try {
151
+ const market = await this.getClobMarket(conditionId);
152
+ if (!market?.tokens?.length || market.tokens.length < 2) {
153
+ return null;
154
+ }
155
+ const primary = market.tokens[0];
156
+ const secondary = market.tokens[1];
157
+ return {
158
+ primaryTokenId: primary.tokenId,
159
+ secondaryTokenId: secondary.tokenId,
160
+ outcomes: [primary.outcome, secondary.outcome],
161
+ primaryOutcome: primary.outcome,
162
+ secondaryOutcome: secondary.outcome,
163
+ };
164
+ }
165
+ catch {
166
+ return null;
167
+ }
168
+ }
73
169
  /**
74
170
  * Get multiple markets from CLOB
75
171
  */
@@ -156,8 +252,12 @@ export class MarketService {
156
252
  */
157
253
  async getProcessedOrderbook(conditionId) {
158
254
  const market = await this.getClobMarket(conditionId);
159
- const yesToken = market.tokens.find(t => t.outcome === 'Yes');
160
- const noToken = market.tokens.find(t => t.outcome === 'No');
255
+ if (!market) {
256
+ throw new PolymarketError(ErrorCode.MARKET_NOT_FOUND, `Market not found: ${conditionId}`);
257
+ }
258
+ // Use index-based access instead of name-based (supports Yes/No, Up/Down, Team1/Team2, etc.)
259
+ const yesToken = market.tokens[0]; // primary outcome
260
+ const noToken = market.tokens[1]; // secondary outcome
161
261
  if (!yesToken || !noToken) {
162
262
  throw new PolymarketError(ErrorCode.INVALID_RESPONSE, 'Missing tokens in market');
163
263
  }
@@ -251,7 +351,10 @@ export class MarketService {
251
351
  }
252
352
  try {
253
353
  const clobMarket = await this.getClobMarket(gammaMarket.conditionId);
254
- return this.mergeMarkets(gammaMarket, clobMarket);
354
+ if (clobMarket) {
355
+ return this.mergeMarkets(gammaMarket, clobMarket);
356
+ }
357
+ return this.fromGammaMarket(gammaMarket);
255
358
  }
256
359
  catch {
257
360
  return this.fromGammaMarket(gammaMarket);
@@ -303,12 +406,36 @@ export class MarketService {
303
406
  // ===== K-Line Aggregation =====
304
407
  /**
305
408
  * Get K-Line candles for a market (single token)
409
+ *
410
+ * @param conditionId - Market condition ID
411
+ * @param interval - K-line interval (1s, 5s, 15s, 30s, 1m, 5m, 15m, 30m, 1h, 4h, 12h, 1d)
412
+ * @param options - Query options
413
+ * @param options.limit - Maximum number of trades to fetch for aggregation (default: 1000)
414
+ * @param options.tokenId - Filter by specific token ID
415
+ * @param options.outcomeIndex - Filter by outcome index (0 = primary, 1 = secondary)
416
+ * @param options.startTimestamp - Start timestamp (Unix ms) - filter trades after this time
417
+ * @param options.endTimestamp - End timestamp (Unix ms) - filter trades before this time
418
+ *
419
+ * @example
420
+ * ```typescript
421
+ * // Get 5s candles for the last 15 minutes
422
+ * const now = Date.now();
423
+ * const candles = await sdk.markets.getKLines(conditionId, '5s', {
424
+ * startTimestamp: now - 15 * 60 * 1000,
425
+ * endTimestamp: now,
426
+ * });
427
+ * ```
306
428
  */
307
429
  async getKLines(conditionId, interval, options) {
308
430
  if (!this.dataApi) {
309
431
  throw new PolymarketError(ErrorCode.INVALID_CONFIG, 'DataApiClient is required for K-Line data');
310
432
  }
311
- const trades = await this.dataApi.getTradesByMarket(conditionId, options?.limit || 1000);
433
+ const trades = await this.dataApi.getTrades({
434
+ market: conditionId,
435
+ limit: options?.limit || 1000,
436
+ startTimestamp: options?.startTimestamp,
437
+ endTimestamp: options?.endTimestamp,
438
+ });
312
439
  // Filter by token/outcome if specified
313
440
  let filteredTrades = trades;
314
441
  if (options?.tokenId) {
@@ -321,16 +448,40 @@ export class MarketService {
321
448
  }
322
449
  /**
323
450
  * Get dual K-Lines (YES + NO tokens)
451
+ *
452
+ * @param conditionId - Market condition ID
453
+ * @param interval - K-line interval (1s, 5s, 15s, 30s, 1m, 5m, 15m, 30m, 1h, 4h, 12h, 1d)
454
+ * @param options - Query options
455
+ * @param options.limit - Maximum number of trades to fetch for aggregation (default: 1000)
456
+ * @param options.startTimestamp - Start timestamp (Unix ms) - filter trades after this time
457
+ * @param options.endTimestamp - End timestamp (Unix ms) - filter trades before this time
458
+ *
459
+ * @example
460
+ * ```typescript
461
+ * // Get 15s dual K-lines for a 15-minute market
462
+ * const now = Date.now();
463
+ * const data = await sdk.markets.getDualKLines(conditionId, '15s', {
464
+ * startTimestamp: now - 15 * 60 * 1000,
465
+ * endTimestamp: now,
466
+ * });
467
+ * console.log(`Up candles: ${data.yes.length}, Down candles: ${data.no.length}`);
468
+ * ```
324
469
  */
325
470
  async getDualKLines(conditionId, interval, options) {
326
471
  if (!this.dataApi) {
327
472
  throw new PolymarketError(ErrorCode.INVALID_CONFIG, 'DataApiClient is required for K-Line data');
328
473
  }
329
474
  const market = await this.getMarket(conditionId);
330
- const trades = await this.dataApi.getTradesByMarket(conditionId, options?.limit || 1000);
331
- // Separate trades by outcome
332
- const yesTrades = trades.filter((t) => t.outcomeIndex === 0 || t.outcome === 'Yes');
333
- const noTrades = trades.filter((t) => t.outcomeIndex === 1 || t.outcome === 'No');
475
+ const trades = await this.dataApi.getTrades({
476
+ market: conditionId,
477
+ limit: options?.limit || 1000,
478
+ startTimestamp: options?.startTimestamp,
479
+ endTimestamp: options?.endTimestamp,
480
+ });
481
+ // Separate trades by outcome using index (more reliable than name matching)
482
+ // outcomeIndex 0 = primary (Yes/Up/Team1), outcomeIndex 1 = secondary (No/Down/Team2)
483
+ const yesTrades = trades.filter((t) => t.outcomeIndex === 0);
484
+ const noTrades = trades.filter((t) => t.outcomeIndex === 1);
334
485
  const yesCandles = this.aggregateToKLines(yesTrades, interval);
335
486
  const noCandles = this.aggregateToKLines(noTrades, interval);
336
487
  // Get current orderbook for real-time spread analysis
@@ -356,15 +507,198 @@ export class MarketService {
356
507
  currentOrderbook,
357
508
  };
358
509
  }
510
+ // ===== Token vs Underlying Correlation =====
511
+ /**
512
+ * Get aligned K-line data for token and underlying asset
513
+ *
514
+ * This method fetches K-line data from both Polymarket (token prices)
515
+ * and Binance (underlying asset prices), aligns them by timestamp,
516
+ * and optionally calculates Pearson correlation coefficients.
517
+ *
518
+ * @param conditionId - Market condition ID
519
+ * @param underlying - Underlying asset (BTC, ETH, SOL)
520
+ * @param interval - K-line interval (must be supported by both Poly and Binance)
521
+ * @param options - Optional parameters
522
+ * @returns Aligned data with optional correlation coefficients
523
+ *
524
+ * @example
525
+ * ```typescript
526
+ * const data = await marketService.getTokenUnderlyingData(
527
+ * '0x123...',
528
+ * 'BTC',
529
+ * '1h',
530
+ * { limit: 100, calculateCorrelation: true }
531
+ * );
532
+ *
533
+ * // Access aligned data
534
+ * for (const point of data.data) {
535
+ * console.log(`${point.timestamp}: Up=${point.upPrice}, BTC=${point.underlyingPrice}`);
536
+ * }
537
+ *
538
+ * // Check correlation
539
+ * if (data.correlation) {
540
+ * console.log(`Correlation: ${data.correlation.upVsUnderlying}`);
541
+ * }
542
+ * ```
543
+ */
544
+ async getTokenUnderlyingData(conditionId, underlying, interval, options) {
545
+ // Validate BinanceService is available
546
+ if (!this.binanceService) {
547
+ throw new PolymarketError(ErrorCode.INVALID_CONFIG, 'BinanceService is required for token-underlying correlation analysis');
548
+ }
549
+ // Validate interval is supported by Binance
550
+ const binanceInterval = KLINE_TO_BINANCE_INTERVAL[interval];
551
+ if (!binanceInterval) {
552
+ throw new PolymarketError(ErrorCode.INVALID_CONFIG, `Interval ${interval} is not supported for correlation analysis. ` +
553
+ `Supported intervals: ${Object.keys(KLINE_TO_BINANCE_INTERVAL).join(', ')}`);
554
+ }
555
+ const limit = options?.limit || 500;
556
+ // Fetch data in parallel
557
+ const [dualKLines, binanceKLines] = await Promise.all([
558
+ this.getDualKLines(conditionId, interval, { limit }),
559
+ this.binanceService.getKLines(UNDERLYING_TO_SYMBOL[underlying], binanceInterval, { limit }),
560
+ ]);
561
+ // Create maps for quick lookup
562
+ const upMap = new Map(dualKLines.yes.map(c => [c.timestamp, c.close]));
563
+ const downMap = new Map(dualKLines.no.map(c => [c.timestamp, c.close]));
564
+ const binanceMap = new Map(binanceKLines.map(c => [c.timestamp, c.close]));
565
+ // Get all unique timestamps and sort them
566
+ const allTimestamps = new Set([
567
+ ...upMap.keys(),
568
+ ...downMap.keys(),
569
+ ...binanceMap.keys(),
570
+ ]);
571
+ const sortedTimestamps = [...allTimestamps].sort((a, b) => a - b);
572
+ // Find the first Binance price for calculating percentage change
573
+ const firstBinancePrice = binanceKLines.length > 0 ? binanceKLines[0].close : 0;
574
+ // Align data points
575
+ const alignedData = [];
576
+ let lastUpPrice;
577
+ let lastDownPrice;
578
+ let lastBinancePrice;
579
+ for (const timestamp of sortedTimestamps) {
580
+ // Get prices, falling back to previous values if not available
581
+ const upPrice = upMap.get(timestamp) ?? this.findNearestPrice(timestamp, upMap, sortedTimestamps);
582
+ const downPrice = downMap.get(timestamp) ?? this.findNearestPrice(timestamp, downMap, sortedTimestamps);
583
+ const binancePrice = binanceMap.get(timestamp) ?? this.findNearestPrice(timestamp, binanceMap, sortedTimestamps);
584
+ // Update last known prices
585
+ if (upPrice !== undefined)
586
+ lastUpPrice = upPrice;
587
+ if (downPrice !== undefined)
588
+ lastDownPrice = downPrice;
589
+ if (binancePrice !== undefined)
590
+ lastBinancePrice = binancePrice;
591
+ // Skip if we don't have underlying price
592
+ if (lastBinancePrice === undefined)
593
+ continue;
594
+ const priceSum = (lastUpPrice !== undefined && lastDownPrice !== undefined)
595
+ ? lastUpPrice + lastDownPrice
596
+ : undefined;
597
+ const underlyingChange = firstBinancePrice > 0
598
+ ? ((lastBinancePrice - firstBinancePrice) / firstBinancePrice) * 100
599
+ : 0;
600
+ alignedData.push({
601
+ timestamp,
602
+ upPrice: lastUpPrice,
603
+ downPrice: lastDownPrice,
604
+ priceSum,
605
+ underlyingPrice: lastBinancePrice,
606
+ underlyingChange,
607
+ });
608
+ }
609
+ // Calculate correlation if requested
610
+ let correlation;
611
+ if (options?.calculateCorrelation && alignedData.length >= 2) {
612
+ correlation = this.calculatePearsonCorrelation(alignedData);
613
+ }
614
+ return {
615
+ conditionId,
616
+ underlying,
617
+ interval,
618
+ data: alignedData,
619
+ correlation,
620
+ };
621
+ }
622
+ /**
623
+ * Find the nearest available price for a timestamp
624
+ */
625
+ findNearestPrice(targetTimestamp, priceMap, sortedTimestamps) {
626
+ if (priceMap.size === 0)
627
+ return undefined;
628
+ // Find the nearest timestamp that has a price
629
+ let nearestTimestamp;
630
+ let minDiff = Infinity;
631
+ for (const ts of sortedTimestamps) {
632
+ if (priceMap.has(ts)) {
633
+ const diff = Math.abs(ts - targetTimestamp);
634
+ if (diff < minDiff) {
635
+ minDiff = diff;
636
+ nearestTimestamp = ts;
637
+ }
638
+ }
639
+ }
640
+ return nearestTimestamp !== undefined ? priceMap.get(nearestTimestamp) : undefined;
641
+ }
642
+ /**
643
+ * Calculate Pearson correlation coefficients
644
+ */
645
+ calculatePearsonCorrelation(data) {
646
+ // Filter data points that have all required prices
647
+ const upData = data.filter(d => d.upPrice !== undefined && d.underlyingPrice !== undefined);
648
+ const downData = data.filter(d => d.downPrice !== undefined && d.underlyingPrice !== undefined);
649
+ const upVsUnderlying = this.pearson(upData.map(d => d.upPrice), upData.map(d => d.underlyingPrice));
650
+ const downVsUnderlying = this.pearson(downData.map(d => d.downPrice), downData.map(d => d.underlyingPrice));
651
+ return {
652
+ upVsUnderlying,
653
+ downVsUnderlying,
654
+ };
655
+ }
656
+ /**
657
+ * Calculate Pearson correlation coefficient between two arrays
658
+ * Returns a value between -1 and 1
659
+ */
660
+ pearson(x, y) {
661
+ const n = Math.min(x.length, y.length);
662
+ if (n < 2)
663
+ return 0;
664
+ // Calculate means
665
+ let sumX = 0, sumY = 0;
666
+ for (let i = 0; i < n; i++) {
667
+ sumX += x[i];
668
+ sumY += y[i];
669
+ }
670
+ const meanX = sumX / n;
671
+ const meanY = sumY / n;
672
+ // Calculate correlation
673
+ let numerator = 0;
674
+ let sumSqX = 0;
675
+ let sumSqY = 0;
676
+ for (let i = 0; i < n; i++) {
677
+ const dx = x[i] - meanX;
678
+ const dy = y[i] - meanY;
679
+ numerator += dx * dy;
680
+ sumSqX += dx * dx;
681
+ sumSqY += dy * dy;
682
+ }
683
+ const denominator = Math.sqrt(sumSqX * sumSqY);
684
+ if (denominator === 0)
685
+ return 0;
686
+ return numerator / denominator;
687
+ }
359
688
  /**
360
689
  * Aggregate trades into K-Line candles
690
+ *
691
+ * Note: Polymarket API may return timestamps in seconds or milliseconds.
692
+ * This function normalizes all timestamps to milliseconds for consistent handling.
361
693
  */
362
694
  aggregateToKLines(trades, interval) {
363
695
  const intervalMs = getIntervalMs(interval);
364
696
  const buckets = new Map();
365
697
  // Group trades into time buckets
698
+ // Normalize timestamp to milliseconds (API sometimes returns seconds)
366
699
  for (const trade of trades) {
367
- const bucketTime = Math.floor(trade.timestamp / intervalMs) * intervalMs;
700
+ const tradeTs = normalizeTimestamp(trade.timestamp);
701
+ const bucketTime = Math.floor(tradeTs / intervalMs) * intervalMs;
368
702
  const bucket = buckets.get(bucketTime) || [];
369
703
  bucket.push(trade);
370
704
  buckets.set(bucketTime, bucket);
@@ -374,8 +708,8 @@ export class MarketService {
374
708
  for (const [timestamp, bucketTrades] of buckets) {
375
709
  if (bucketTrades.length === 0)
376
710
  continue;
377
- // Sort by timestamp for correct open/close
378
- bucketTrades.sort((a, b) => a.timestamp - b.timestamp);
711
+ // Sort by normalized timestamp for correct open/close
712
+ bucketTrades.sort((a, b) => normalizeTimestamp(a.timestamp) - normalizeTimestamp(b.timestamp));
379
713
  const prices = bucketTrades.map((t) => t.price);
380
714
  const buyTrades = bucketTrades.filter((t) => t.side === 'BUY');
381
715
  const sellTrades = bucketTrades.filter((t) => t.side === 'SELL');
@@ -540,6 +874,148 @@ export class MarketService {
540
874
  }
541
875
  return this.gammaApi.getMarkets(params);
542
876
  }
877
+ /**
878
+ * Scan for short-term crypto markets (Up/Down markets ending soon)
879
+ *
880
+ * ## Market Types
881
+ * Polymarket has short-term crypto markets in two durations:
882
+ * - **5-minute markets**: slug pattern `{coin}-updown-5m-{timestamp}`
883
+ * - **15-minute markets**: slug pattern `{coin}-updown-15m-{timestamp}`
884
+ *
885
+ * ## Slug Pattern
886
+ * The timestamp in the slug is the START time of the time window:
887
+ * - 15-minute markets: `{coin}-updown-15m-{Math.floor(startTime / 900) * 900}`
888
+ * - 5-minute markets: `{coin}-updown-5m-{Math.floor(startTime / 300) * 300}`
889
+ *
890
+ * Example: `btc-updown-15m-1767456000` starts at 1767456000 (16:00:00 UTC)
891
+ * and ends 15 minutes later at 1767456900 (16:15:00 UTC)
892
+ *
893
+ * ## Supported Coins
894
+ * - BTC (Bitcoin)
895
+ * - ETH (Ethereum)
896
+ * - SOL (Solana)
897
+ * - XRP (Ripple)
898
+ *
899
+ * ## Market Lifecycle Rules
900
+ * 1. Markets are created ahead of time (before they become tradeable)
901
+ * 2. New markets may not have prices yet (show 0.5/0.5)
902
+ * 3. When one market ends, the next one is already open for trading
903
+ * 4. A market ending doesn't mean no price - it means resolution is pending
904
+ *
905
+ * ## Outcomes
906
+ * All crypto short-term markets have:
907
+ * - outcomes: ["Up", "Down"]
908
+ * - Resolution based on price movement during the time window
909
+ *
910
+ * @param options - Scan options
911
+ * @param options.minMinutesUntilEnd - Minimum minutes until market ends (default: 5)
912
+ * @param options.maxMinutesUntilEnd - Maximum minutes until market ends (default: 60)
913
+ * @param options.limit - Maximum number of markets to return (default: 20)
914
+ * @param options.sortBy - Sort field: 'endDate' | 'volume' | 'liquidity' (default: 'endDate')
915
+ * @param options.duration - Filter by duration: '5m' | '15m' | 'all' (default: 'all')
916
+ * @param options.coin - Filter by coin: 'BTC' | 'ETH' | 'SOL' | 'XRP' | 'all' (default: 'all')
917
+ * @returns Array of crypto short-term markets
918
+ *
919
+ * @example
920
+ * ```typescript
921
+ * // Find all 15-minute markets ending in 5-30 minutes
922
+ * const markets = await sdk.markets.scanCryptoShortTermMarkets({
923
+ * minMinutesUntilEnd: 5,
924
+ * maxMinutesUntilEnd: 30,
925
+ * duration: '15m',
926
+ * });
927
+ *
928
+ * // Find BTC 5-minute markets only
929
+ * const btcMarkets = await sdk.markets.scanCryptoShortTermMarkets({
930
+ * coin: 'BTC',
931
+ * duration: '5m',
932
+ * });
933
+ * ```
934
+ */
935
+ async scanCryptoShortTermMarkets(options) {
936
+ if (!this.gammaApi) {
937
+ throw new PolymarketError(ErrorCode.INVALID_CONFIG, 'GammaApiClient is required for market scanning');
938
+ }
939
+ const { minMinutesUntilEnd = 5, maxMinutesUntilEnd = 60, limit = 20, sortBy = 'endDate', duration = 'all', coin = 'all', } = options ?? {};
940
+ // Duration to interval seconds mapping
941
+ const durationIntervals = {
942
+ '5m': 300, // 5 minutes in seconds
943
+ '15m': 900, // 15 minutes in seconds
944
+ };
945
+ // Supported coins
946
+ const allCoins = ['btc', 'eth', 'sol', 'xrp'];
947
+ const targetCoins = coin === 'all' ? allCoins : [coin.toLowerCase()];
948
+ // Target durations
949
+ const targetDurations = duration === 'all' ? ['5m', '15m'] : [duration];
950
+ // Calculate time slots to fetch
951
+ const nowSeconds = Math.floor(Date.now() / 1000);
952
+ const minEndSeconds = nowSeconds + minMinutesUntilEnd * 60;
953
+ const maxEndSeconds = nowSeconds + maxMinutesUntilEnd * 60;
954
+ // Generate slugs for all combinations
955
+ const slugsToFetch = [];
956
+ for (const dur of targetDurations) {
957
+ const intervalSeconds = durationIntervals[dur];
958
+ const durationStr = dur.replace('m', 'm'); // 5m or 15m
959
+ // Calculate the current slot and extend to cover the time range
960
+ // The slug timestamp is the START time, endTime = startTime + interval
961
+ // So if we want markets ending after minEndSeconds:
962
+ // startTime + interval >= minEndSeconds => startTime >= minEndSeconds - interval
963
+ // And ending before maxEndSeconds:
964
+ // startTime + interval <= maxEndSeconds => startTime <= maxEndSeconds - interval
965
+ const minSlotStart = Math.floor((minEndSeconds - intervalSeconds) / intervalSeconds) * intervalSeconds;
966
+ const maxSlotStart = Math.ceil(maxEndSeconds / intervalSeconds) * intervalSeconds;
967
+ // Generate slots from minSlotStart to maxSlotStart
968
+ for (let slotStart = minSlotStart; slotStart <= maxSlotStart; slotStart += intervalSeconds) {
969
+ for (const coinName of targetCoins) {
970
+ slugsToFetch.push(`${coinName}-updown-${durationStr}-${slotStart}`);
971
+ }
972
+ }
973
+ }
974
+ // Fetch markets in parallel batches
975
+ const BATCH_SIZE = 10;
976
+ const allMarkets = [];
977
+ for (let i = 0; i < slugsToFetch.length; i += BATCH_SIZE) {
978
+ const batch = slugsToFetch.slice(i, i + BATCH_SIZE);
979
+ const results = await Promise.all(batch.map(async (slug) => {
980
+ try {
981
+ const markets = await this.gammaApi.getMarkets({ slug, limit: 1 });
982
+ return markets.length > 0 ? markets[0] : null;
983
+ }
984
+ catch {
985
+ return null;
986
+ }
987
+ }));
988
+ for (const market of results) {
989
+ if (market && market.active && !market.closed) {
990
+ allMarkets.push(market);
991
+ }
992
+ }
993
+ }
994
+ // Filter by end time range
995
+ const nowMs = Date.now();
996
+ const minEndTime = nowMs + minMinutesUntilEnd * 60 * 1000;
997
+ const maxEndTime = nowMs + maxMinutesUntilEnd * 60 * 1000;
998
+ const filteredMarkets = allMarkets.filter((market) => {
999
+ const endTime = market.endDate ? new Date(market.endDate).getTime() : 0;
1000
+ return endTime >= minEndTime && endTime <= maxEndTime;
1001
+ });
1002
+ // Sort by preference
1003
+ if (sortBy === 'volume') {
1004
+ filteredMarkets.sort((a, b) => (b.volume24hr ?? 0) - (a.volume24hr ?? 0));
1005
+ }
1006
+ else if (sortBy === 'liquidity') {
1007
+ filteredMarkets.sort((a, b) => (b.liquidity ?? 0) - (a.liquidity ?? 0));
1008
+ }
1009
+ else {
1010
+ // Sort by endDate (soonest first)
1011
+ filteredMarkets.sort((a, b) => {
1012
+ const aEnd = a.endDate ? new Date(a.endDate).getTime() : Infinity;
1013
+ const bEnd = b.endDate ? new Date(b.endDate).getTime() : Infinity;
1014
+ return aEnd - bEnd;
1015
+ });
1016
+ }
1017
+ return filteredMarkets.slice(0, limit);
1018
+ }
543
1019
  // ===== Market Signal Detection =====
544
1020
  /**
545
1021
  * Detect market signals (volume surge, depth imbalance, whale trades)
@@ -706,10 +1182,12 @@ export class MarketService {
706
1182
  };
707
1183
  }
708
1184
  fromGammaMarket(gamma) {
709
- // Create tokens from Gamma outcomes (binary market: Yes/No)
1185
+ // Create tokens from Gamma outcomes - use actual outcome names from gamma data
1186
+ // This supports Yes/No, Up/Down, Team1/Team2, Heads/Tails, etc.
1187
+ const outcomes = gamma.outcomes || ['Yes', 'No'];
710
1188
  const tokens = [
711
- { tokenId: '', outcome: 'Yes', price: gamma.outcomePrices[0] || 0.5 },
712
- { tokenId: '', outcome: 'No', price: gamma.outcomePrices[1] || 0.5 },
1189
+ { tokenId: '', outcome: outcomes[0], price: gamma.outcomePrices[0] || 0.5 },
1190
+ { tokenId: '', outcome: outcomes[1], price: gamma.outcomePrices[1] || 0.5 },
713
1191
  ];
714
1192
  return {
715
1193
  conditionId: gamma.conditionId,
@@ -759,11 +1237,17 @@ export class MarketService {
759
1237
  // ===== Utility Functions =====
760
1238
  export function getIntervalMs(interval) {
761
1239
  const map = {
1240
+ // Second-level intervals (for 15-minute crypto markets)
1241
+ '1s': 1 * 1000,
1242
+ '5s': 5 * 1000,
1243
+ '15s': 15 * 1000,
762
1244
  '30s': 30 * 1000,
1245
+ // Minute-level intervals
763
1246
  '1m': 60 * 1000,
764
1247
  '5m': 5 * 60 * 1000,
765
1248
  '15m': 15 * 60 * 1000,
766
1249
  '30m': 30 * 60 * 1000,
1250
+ // Hour-level intervals
767
1251
  '1h': 60 * 60 * 1000,
768
1252
  '4h': 4 * 60 * 60 * 1000,
769
1253
  '12h': 12 * 60 * 60 * 1000,