@tradelayerprotocol/tradelayer 1.9.1

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 (249) hide show
  1. package/.claude/settings.local.json +13 -0
  2. package/.claude/skills/tl-algo/SKILL.md +255 -0
  3. package/.gitattributes +2 -0
  4. package/.github/workflows/publish.yaml +26 -0
  5. package/4mm.js +163 -0
  6. package/LICENSE +21 -0
  7. package/NPMSwapRefactor.zip +0 -0
  8. package/README.md +217 -0
  9. package/address.sh +26 -0
  10. package/algoAPI.js +581 -0
  11. package/analyzepsbt.js +92 -0
  12. package/apiEx.js +99 -0
  13. package/bb_hyperscalper.js +290 -0
  14. package/bbo_demo.js +111 -0
  15. package/buyer.js +622 -0
  16. package/client.js +50 -0
  17. package/createTxTest.js +26 -0
  18. package/createWallet.js +75 -0
  19. package/daytrader.js +531 -0
  20. package/decodeTest.js +69 -0
  21. package/fundingManager.js +144 -0
  22. package/index.js +4 -0
  23. package/listener.js +27 -0
  24. package/litecoreTxBuilder.js +1128 -0
  25. package/mmEx.js +356 -0
  26. package/networks.js +51 -0
  27. package/orderbook.js +200 -0
  28. package/package.json +34 -0
  29. package/perTradeQueue.js +36 -0
  30. package/projectsTLNPMTLNPM/package-lock.json +162 -0
  31. package/projectsTLNPMTLNPM/package.json +5 -0
  32. package/quick.js +32 -0
  33. package/quickFut.js +37 -0
  34. package/quickSell.js +37 -0
  35. package/relayerClient.js +117 -0
  36. package/run4mm.js +80 -0
  37. package/run_bbo_tracker.js +241 -0
  38. package/seller.js +443 -0
  39. package/session.js +45 -0
  40. package/setup-lin-ltc.sh +139 -0
  41. package/setup-lin.sh +203 -0
  42. package/setup-win-ltc.bat +108 -0
  43. package/setup-win.bat +167 -0
  44. package/spam_screamer_futures.js +222 -0
  45. package/tradelayer.js/.gitattributes +2 -0
  46. package/tradelayer.js/README.md +2 -0
  47. package/tradelayer.js/oldTests/activationTest.js +6 -0
  48. package/tradelayer.js/oldTests/base58.test.js +23 -0
  49. package/tradelayer.js/oldTests/base64Decode.test.js +16 -0
  50. package/tradelayer.js/oldTests/blocksRefactor.js +140 -0
  51. package/tradelayer.js/oldTests/checkVestBalance.js +25 -0
  52. package/tradelayer.js/oldTests/consensusHashProto.js +151 -0
  53. package/tradelayer.js/oldTests/contractOrderbook.js +243 -0
  54. package/tradelayer.js/oldTests/createPayload.js +0 -0
  55. package/tradelayer.js/oldTests/createTestnetAddr.js +43 -0
  56. package/tradelayer.js/oldTests/decode.js +205 -0
  57. package/tradelayer.js/oldTests/decodeTest.js +50 -0
  58. package/tradelayer.js/oldTests/displayTallyMap.js +19 -0
  59. package/tradelayer.js/oldTests/encodeDecode.js +340 -0
  60. package/tradelayer.js/oldTests/expressTest.js +29 -0
  61. package/tradelayer.js/oldTests/extractBlocksVanilla.js +214 -0
  62. package/tradelayer.js/oldTests/extractBlocksVanillaa.js +179 -0
  63. package/tradelayer.js/oldTests/extractPubkeyTest.js +60 -0
  64. package/tradelayer.js/oldTests/fillInputCacheProto.js +111 -0
  65. package/tradelayer.js/oldTests/getRawTxTest.js +22 -0
  66. package/tradelayer.js/oldTests/indexTest.js +26 -0
  67. package/tradelayer.js/oldTests/initTokensTest.js +32 -0
  68. package/tradelayer.js/oldTests/interfaceChild.js +129 -0
  69. package/tradelayer.js/oldTests/listenerChild.js +112 -0
  70. package/tradelayer.js/oldTests/opdecode.js +26 -0
  71. package/tradelayer.js/oldTests/options.js +79 -0
  72. package/tradelayer.js/oldTests/optxtest.js +116 -0
  73. package/tradelayer.js/oldTests/optxtest1.js +64 -0
  74. package/tradelayer.js/oldTests/oracle.test.js +32 -0
  75. package/tradelayer.js/oldTests/orderbook.test.js +36 -0
  76. package/tradelayer.js/oldTests/parsing.js +93 -0
  77. package/tradelayer.js/oldTests/payload.js +13 -0
  78. package/tradelayer.js/oldTests/persistenceUnitTest.js +23 -0
  79. package/tradelayer.js/oldTests/property.test.js +53 -0
  80. package/tradelayer.js/oldTests/propertyLevel.js +75 -0
  81. package/tradelayer.js/oldTests/propertyTest.js +32 -0
  82. package/tradelayer.js/oldTests/queryAddressTest.js +17 -0
  83. package/tradelayer.js/oldTests/salter.js +14 -0
  84. package/tradelayer.js/oldTests/tally.js +81 -0
  85. package/tradelayer.js/oldTests/tally.test.js +48 -0
  86. package/tradelayer.js/oldTests/tally2.js +124 -0
  87. package/tradelayer.js/oldTests/tally3.js +142 -0
  88. package/tradelayer.js/oldTests/tallyDiag.js +38 -0
  89. package/tradelayer.js/oldTests/testGetRaw.js +40 -0
  90. package/tradelayer.js/oldTests/testHexConvert.js +47 -0
  91. package/tradelayer.js/oldTests/testNewEncoding.js +96 -0
  92. package/tradelayer.js/oldTests/testNewEncoding2.js +113 -0
  93. package/tradelayer.js/oldTests/testNewEncoding3 +112 -0
  94. package/tradelayer.js/oldTests/testNewEncoding3.js +168 -0
  95. package/tradelayer.js/oldTests/testOPReturn.js +102 -0
  96. package/tradelayer.js/oldTests/testPayload.js +23 -0
  97. package/tradelayer.js/oldTests/testRaw.js +50 -0
  98. package/tradelayer.js/oldTests/testSendTooMuch.js +20 -0
  99. package/tradelayer.js/oldTests/testTxBuild +28 -0
  100. package/tradelayer.js/oldTests/testTxBuild.js +42 -0
  101. package/tradelayer.js/oldTests/tokenOrderbook.js +243 -0
  102. package/tradelayer.js/oldTests/txUtilsA.js +515 -0
  103. package/tradelayer.js/oldTests/validityUnitTest.js +53 -0
  104. package/tradelayer.js/oldTests/vaults.js +72 -0
  105. package/tradelayer.js/oldTests/volumeIndex.js +117 -0
  106. package/tradelayer.js/oldTests/volumeIndex2.js +88 -0
  107. package/tradelayer.js/output_base64.txt +1 -0
  108. package/tradelayer.js/package-lock.json +9967 -0
  109. package/tradelayer.js/package.json +61 -0
  110. package/tradelayer.js/server/index.js +88 -0
  111. package/tradelayer.js/server/litecoind.exe +0 -0
  112. package/tradelayer.js/src/activation.js +303 -0
  113. package/tradelayer.js/src/adjuster.js +77 -0
  114. package/tradelayer.js/src/amm.js +400 -0
  115. package/tradelayer.js/src/base256.js +55 -0
  116. package/tradelayer.js/src/base94.js +79 -0
  117. package/tradelayer.js/src/channels.js +1163 -0
  118. package/tradelayer.js/src/clearing.js +3109 -0
  119. package/tradelayer.js/src/clearlist.js +364 -0
  120. package/tradelayer.js/src/client.js +295 -0
  121. package/tradelayer.js/src/consensus.js +613 -0
  122. package/tradelayer.js/src/contractRegistry.js +964 -0
  123. package/tradelayer.js/src/db.js +89 -0
  124. package/tradelayer.js/src/init.js +24 -0
  125. package/tradelayer.js/src/insurance.js +347 -0
  126. package/tradelayer.js/src/interface.js +218 -0
  127. package/tradelayer.js/src/interfaceExpress.js +178 -0
  128. package/tradelayer.js/src/iou.js +509 -0
  129. package/tradelayer.js/src/listener.js +226 -0
  130. package/tradelayer.js/src/logic.js +1702 -0
  131. package/tradelayer.js/src/main.js +927 -0
  132. package/tradelayer.js/src/marginMap.js +2165 -0
  133. package/tradelayer.js/src/options.js +126 -0
  134. package/tradelayer.js/src/oracle.js +394 -0
  135. package/tradelayer.js/src/orderbook.js +4123 -0
  136. package/tradelayer.js/src/persistence.js +554 -0
  137. package/tradelayer.js/src/property.js +411 -0
  138. package/tradelayer.js/src/reOrg.js +41 -0
  139. package/tradelayer.js/src/scaling.js +145 -0
  140. package/tradelayer.js/src/tally.js +1275 -0
  141. package/tradelayer.js/src/tradeHistoryManager.js +552 -0
  142. package/tradelayer.js/src/txDecoder.js +584 -0
  143. package/tradelayer.js/src/txEncoder.js +610 -0
  144. package/tradelayer.js/src/txIndex.js +502 -0
  145. package/tradelayer.js/src/txUtils.js +1392 -0
  146. package/tradelayer.js/src/types.js +429 -0
  147. package/tradelayer.js/src/validity.js +3077 -0
  148. package/tradelayer.js/src/vaults.js +430 -0
  149. package/tradelayer.js/src/vesting.js +491 -0
  150. package/tradelayer.js/src/volumeIndex.js +618 -0
  151. package/tradelayer.js/src/walletInterface.js +220 -0
  152. package/tradelayer.js/src/walletListener.js +665 -0
  153. package/tradelayer.js/tests/256decode.js +82 -0
  154. package/tradelayer.js/tests/UTXOracle.js +205 -0
  155. package/tradelayer.js/tests/base94test.js +23 -0
  156. package/tradelayer.js/tests/cancelTxTest.js +62 -0
  157. package/tradelayer.js/tests/contractInterfaceTest.js +48 -0
  158. package/tradelayer.js/tests/decimalTest.js +65 -0
  159. package/tradelayer.js/tests/decoderTest.js +100 -0
  160. package/tradelayer.js/tests/deltaCount.js +47 -0
  161. package/tradelayer.js/tests/deltaCount2.js +60 -0
  162. package/tradelayer.js/tests/interfaceTest.js +37 -0
  163. package/tradelayer.js/tests/mainTest.js +53 -0
  164. package/tradelayer.js/tests/makeActivationTest.js +24 -0
  165. package/tradelayer.js/tests/maxHeightTest.js +49 -0
  166. package/tradelayer.js/tests/reverseHash.js +72 -0
  167. package/tradelayer.js/tests/sensitiveConsoleOutput.txt +267 -0
  168. package/tradelayer.js/tests/tallyTest.js +40 -0
  169. package/tradelayer.js/tests/testBuybacks.js +46 -0
  170. package/tradelayer.js/tests/testCodeHash.js +49 -0
  171. package/tradelayer.js/tests/testConsensusHash.js +91 -0
  172. package/tradelayer.js/tests/testDecode.js +30 -0
  173. package/tradelayer.js/tests/testEncodingLengths.js +129 -0
  174. package/tradelayer.js/tests/testGetTx +32 -0
  175. package/tradelayer.js/tests/testGetTx.js +32 -0
  176. package/tradelayer.js/tests/testHexHash.js +32 -0
  177. package/tradelayer.js/tests/testIndexHash.js +35 -0
  178. package/tradelayer.js/tests/testInitContracts.js +38 -0
  179. package/tradelayer.js/tests/testMaxConsensus.js +12 -0
  180. package/tradelayer.js/tests/testMaxSynth.js +44 -0
  181. package/tradelayer.js/tests/testMint.js +21 -0
  182. package/tradelayer.js/tests/testNetwork.js +33 -0
  183. package/tradelayer.js/tests/testOrderbookLoad.js +62 -0
  184. package/tradelayer.js/tests/testRebates.js +32 -0
  185. package/tradelayer.js/tests/testRedeem.js +22 -0
  186. package/tradelayer.js/tests/testTokenTrade.js +39 -0
  187. package/tradelayer.js/tests/testTxBuild.js +42 -0
  188. package/tradelayer.js/tests/testUTXOTrade.js +27 -0
  189. package/tradelayer.js/tests/tokenTradeHistory.js +27 -0
  190. package/tradelayer.js/tests/tradeFutures.js +40 -0
  191. package/tradelayer.js/tests/tradeHistoryExample.js +35 -0
  192. package/tradelayer.js/tests/tradeHistoryLoad.js +15 -0
  193. package/tradelayer.js/tests/txScanTest.js +134 -0
  194. package/tradelayer.js/tests/validateTest.js +136 -0
  195. package/tradelayer.js/tests/vestingTest.js +37 -0
  196. package/tradelayer.js/utils/activateMainnet.js +59 -0
  197. package/tradelayer.js/utils/activateMainnetDoge.js +63 -0
  198. package/tradelayer.js/utils/autocompactdb.js +23 -0
  199. package/tradelayer.js/utils/base64toHex.js +32 -0
  200. package/tradelayer.js/utils/broadcastDoge.js +38 -0
  201. package/tradelayer.js/utils/calcRedeem.js +19 -0
  202. package/tradelayer.js/utils/checkNetwork.js +27 -0
  203. package/tradelayer.js/utils/createAddress.js +48 -0
  204. package/tradelayer.js/utils/createAttestation.js +133 -0
  205. package/tradelayer.js/utils/createContract.js +118 -0
  206. package/tradelayer.js/utils/createOracle.js +94 -0
  207. package/tradelayer.js/utils/createwallet.js +20 -0
  208. package/tradelayer.js/utils/crossFuturesTrades.js +57 -0
  209. package/tradelayer.js/utils/crossTokenTrades.js +62 -0
  210. package/tradelayer.js/utils/dumpPriv.js +29 -0
  211. package/tradelayer.js/utils/generateChannel.js +34 -0
  212. package/tradelayer.js/utils/getInfo.js +21 -0
  213. package/tradelayer.js/utils/hardWipe.js +20 -0
  214. package/tradelayer.js/utils/hexTo64.js +16 -0
  215. package/tradelayer.js/utils/importAddress.js +28 -0
  216. package/tradelayer.js/utils/importpriv.js +20 -0
  217. package/tradelayer.js/utils/issueOracleContract.js +67 -0
  218. package/tradelayer.js/utils/issueTokens.js +41 -0
  219. package/tradelayer.js/utils/listunspent.js +66 -0
  220. package/tradelayer.js/utils/litecoinClient.js +30 -0
  221. package/tradelayer.js/utils/loadwallet.js +20 -0
  222. package/tradelayer.js/utils/publishOracle.js +113 -0
  223. package/tradelayer.js/utils/sendActivation.js +21 -0
  224. package/tradelayer.js/utils/sendChannelContractTrade.js +34 -0
  225. package/tradelayer.js/utils/sendChannelTokenTrade.js +34 -0
  226. package/tradelayer.js/utils/sendCommit.js +24 -0
  227. package/tradelayer.js/utils/sendDoge.js +62 -0
  228. package/tradelayer.js/utils/sendDogeMain.js +67 -0
  229. package/tradelayer.js/utils/sendDogeTx.js +46 -0
  230. package/tradelayer.js/utils/sendLTC.js +63 -0
  231. package/tradelayer.js/utils/sendMainnet.js +62 -0
  232. package/tradelayer.js/utils/sendTransfer.js +19 -0
  233. package/tradelayer.js/utils/sendVestTest.js +88 -0
  234. package/tradelayer.js/utils/sendWithdrawal.js +26 -0
  235. package/tradelayer.js/utils/simpleStart.js +8 -0
  236. package/tradelayer.js/utils/startStop.js +27 -0
  237. package/tradelayer.js/utils/structuredTrades.js +136 -0
  238. package/tradelayer.js/utils/verifySignature.js +90 -0
  239. package/tradelayer.js/utils/verifyWitnessAndScriptPubkey.js +41 -0
  240. package/tradelayer.js/utils/walletCache.js +172 -0
  241. package/tradelayer.js/utils/walletContractInterface.js +48 -0
  242. package/tradelayer.js/utils/walletFetchTxs.js +66 -0
  243. package/tradelayer.js/utils/walletUtils.js +97 -0
  244. package/tradelayer.js/utils/wipeDB.js +55 -0
  245. package/tradelayer.js/utils/wipeDBNotTx.js +50 -0
  246. package/txEncoder.js +529 -0
  247. package/utility.js +28 -0
  248. package/verifymessage.js +38 -0
  249. package/ws-transport.js +311 -0
@@ -0,0 +1,552 @@
1
+ const dbInstance = require('./db.js')
2
+ const BigNumber = require('bignumber.js');
3
+
4
+ class TradeHistory {
5
+
6
+ async loadTradeHistory(contractId) {
7
+ const stringKey = `contract-${contractId}`;
8
+ console.log('key to load trades ' + JSON.stringify({ key: stringKey }));
9
+
10
+ const tradeHistoryDB = await dbInstance.getDatabase('tradeHistory');
11
+
12
+ // Try single doc per contract
13
+ const doc = await tradeHistoryDB.findOneAsync({ _id: stringKey });
14
+ if (doc) {
15
+ if (Array.isArray(doc.trades)) return doc.trades;
16
+ if (doc.trade) return [doc.trade];
17
+ return [doc];
18
+ }
19
+
20
+ // Legacy fallback: docs with prefix contract-<id>-
21
+ if (typeof tradeHistoryDB.findAsync === 'function') {
22
+ const re = new RegExp(`^${stringKey}-`);
23
+ const legacyRows = await tradeHistoryDB.findAsync({ _id: { $regex: re } });
24
+ if (legacyRows && legacyRows.length) {
25
+ return legacyRows.map(r => r.trade ?? r);
26
+ }
27
+ }
28
+
29
+
30
+ // Last resort: filter whole db
31
+ const all = await dbInstance.getDatabase('tradeHistory');
32
+ return (Array.isArray(all) ? all : [])
33
+ .filter(r => r?.key === stringKey || String(r?._id || '').startsWith(`${stringKey}-`))
34
+ .map(r => r.trade ?? r);
35
+ }
36
+
37
+ async getTradeHistoryForAddress(address, contractId) {
38
+ console.log('about to call load history for contract ' + contractId);
39
+ const trades = await this.loadTradeHistory(contractId);
40
+
41
+ return trades.filter(t => {
42
+ const buyer = t?.buyer || t?.buyerAddress || t?.counterpartyAddress;
43
+ const seller = t?.seller || t?.sellerAddress || t?.liquidatingAddress;
44
+ return buyer === address || seller === address;
45
+ });
46
+ }
47
+
48
+
49
+ // Order-independent token pair + address filter
50
+ static async getTokenTradeHistoryForAddress(propertyId1, propertyId2, address) {
51
+ try{
52
+ const tradeDB = await dbInstance.getDatabase('tradeHistory');
53
+
54
+ // Support either pair ordering
55
+ const a = Number(propertyId1);
56
+ const b = Number(propertyId2);
57
+ const keys = [`token-${a}-${b}`, `token-${b}-${a}`];
58
+
59
+ const addr = String(address || '');
60
+ const addrL = addr.toLowerCase();
61
+
62
+ const docs = await tradeDB.findAsync({
63
+ $and: [
64
+ { key: { $in: keys } },
65
+ {
66
+ $or: [
67
+ { 'trade.buyer': addr },
68
+ { 'trade.seller': addr },
69
+ { 'trade.buyer': addrL },
70
+ { 'trade.seller': addrL },
71
+ ]
72
+ }
73
+ ]
74
+ });
75
+
76
+ return (docs || []).map(d => d.trade);
77
+ }catch{
78
+ return "error in trade manager"
79
+ }
80
+ }
81
+
82
+ // Contract + address filter
83
+ static async getContractTradeHistoryForAddress(contractId, address) {
84
+ const tradeDB = await dbInstance.getDatabase('tradeHistory');
85
+
86
+ const key = `contract-${contractId}`;
87
+ const addr = String(address || '');
88
+ const addrL = addr.toLowerCase();
89
+
90
+ const docs = await tradeDB.findAsync({
91
+ $and: [
92
+ { key },
93
+ {
94
+ $or: [
95
+ { 'trade.buyer': addr },
96
+ { 'trade.seller': addr },
97
+ { 'trade.buyer': addrL },
98
+ { 'trade.seller': addrL },
99
+ ]
100
+ }
101
+ ]
102
+ });
103
+
104
+ return (docs || []).map(d => d.trade);
105
+ }
106
+
107
+
108
+ async getPositionHistoryForContract(address, contractId) {
109
+ //console.log('about to call trade history for contract '+contractId)
110
+ const addressTradeHistory = await this.getTradeHistoryForAddress(address,contractId);
111
+ addressTradeHistory.sort((a, b) => a.blockHeight - b.blockHeight);
112
+
113
+ //console.log('filtered trade history for address '+address+ ' ' +JSON.stringify(addressTradeHistory))
114
+ const positionHistory = [];
115
+ var position = 0
116
+
117
+ for (const trade of addressTradeHistory) {
118
+ //console.log(JSON.stringify(trade))
119
+ if (trade.trade.contractId === contractId) {
120
+ if(trade.trade.sellerAddress==address){
121
+ trade.trade.amount *= -1
122
+ }
123
+ // Check if the trade is a close
124
+ const isClose = Math.abs(position) > Math.abs(position + trade.trade.amount);
125
+ //console.log(Math.abs(position) + ' '+ Math.abs(position +trade.trade.amount))
126
+ position = position + trade.trade.amount
127
+
128
+ const snapshot = {
129
+ amount: position,
130
+ price: trade.trade.price,
131
+ blockHeight: trade.blockHeight,
132
+ isClose: isClose
133
+ };
134
+ //console.log(snapshot)
135
+ positionHistory.push(snapshot);
136
+
137
+ }
138
+ }
139
+ //console.log(positionHistory)
140
+ return positionHistory;
141
+ }
142
+
143
+ async getTxIdsForContract(address, contractId, action) {
144
+ const addressTradeHistory = await this.getTradeHistoryForAddress(address);
145
+ const txIds = [];
146
+
147
+ for (const trade of addressTradeHistory) {
148
+ if (trade.trade.contractId === contractId && trade.trade.buyerAddress === address) {
149
+ txIds.push({
150
+ txId: trade.trade.buyerTx,
151
+ blockHeight: trade.blockHeight,
152
+ });
153
+ }else if(trade.trade.contractId === contractId && trade.trade.sellerAddress === address){
154
+ txIds.push({
155
+ txId: trade.trade.sellerTx,
156
+ blockHeight: trade.blockHeight,
157
+ });
158
+ }
159
+ }
160
+
161
+ return txIds;
162
+ }
163
+ async getCategorizedTrades(address, contractId) {
164
+ const trades = await this.getTradeHistoryForAddress(address, contractId);
165
+
166
+ let openTrades = [];
167
+ let closeTrades = [];
168
+
169
+ for (let i = 0; i < trades.length; i++) {
170
+ const currentTrade = trades[i].trade;
171
+ console.log('checking currentTrade'+JSON.stringify(currentTrade))
172
+ let individualTrade = {
173
+ address: '',
174
+ contractId: currentTrade.contractId,
175
+ price: currentTrade.price,
176
+ amount: 0,
177
+ block: currentTrade.block,
178
+ fullyClosesPosition: false,
179
+ };
180
+
181
+ if (currentTrade.buyerClose == 0&&currentTrade.buyerAddress==address) {
182
+ individualTrade.amount = currentTrade.amount;
183
+ individualTrade.address = currentTrade.buyerAddress;
184
+ openTrades.push(individualTrade);
185
+ } else if((currentTrade.buyerClose>0||currentTrade.buyerClose==null)&&currentTrade.buyerAddress==address){
186
+ individualTrade.amount = currentTrade.buyerClosed;
187
+ individualTrade.address = currentTrade.buyerAddress;
188
+ individualTrade.fullyClosesPosition = currentTrade.buyerFullClose;
189
+ closeTrades.push(individualTrade);
190
+ if (currentTrade.flipLong > 0) {
191
+ // flip trade
192
+ console.log('flip long before ajustment '+JSON.stringify(individualTrade))
193
+ individualTrade.amount = currentTrade.flipLong;
194
+ individualTrade.address = currentTrade.buyerAddress;
195
+ individualTrade.fullyClosesPosition = true;
196
+ console.log('flip long after adjustment '+JSON.stringify(individualTrade))
197
+ openTrades.push(individualTrade);
198
+ }
199
+ }
200
+
201
+ if (currentTrade.sellerClose == 0&&currentTrade.sellerAddress==address) {
202
+ individualTrade.amount = currentTrade.amount*-1;
203
+ individualTrade.address = currentTrade.sellerAddress;
204
+ openTrades.push(individualTrade);
205
+ } else if((currentTrade.sellerClose>0||currentTrade.sellerClose==null)&&currentTrade.sellerAddress==address){
206
+ individualTrade.amount = currentTrade.sellerClosed*-1;
207
+ individualTrade.address = currentTrade.sellerAddress;
208
+ individualTrade.fullyClosesPosition = currentTrade.sellerFullClose;
209
+ closeTrades.push(individualTrade);
210
+ if (currentTrade.flipShort> 0) {
211
+ // flip trade
212
+ individualTrade.amount = currentTrade.sellerClosed*-1;
213
+ individualTrade.address = currentTrade.sellerAddress;
214
+ individualTrade.fullyClosesPosition = true;
215
+ openTrades.push(individualTrade);
216
+ }
217
+ }
218
+ }
219
+
220
+ // Sort open and close trades by block height
221
+ openTrades.sort((a, b) => a.block - b.block);
222
+ closeTrades.sort((a, b) => a.block - b.block);
223
+
224
+ const categorizedTrades = {
225
+ openTrades: openTrades,
226
+ closeTrades: closeTrades,
227
+ };
228
+
229
+ return categorizedTrades;
230
+ }
231
+
232
+
233
+ computeAverageEntryPrices(openTrades) {
234
+ let sum = new BigNumber(0);
235
+ let count = new BigNumber(0);
236
+
237
+ for (let i = 0; i < openTrades.length; i++) {
238
+ const trade = openTrades[i];
239
+ const price = new BigNumber(trade.price);
240
+ const amount = new BigNumber(trade.amount);
241
+
242
+ sum = sum.plus(price.times(amount.abs()));;
243
+ count = count.plus(amount.abs());
244
+ }
245
+
246
+ const avgEntryPrice = count.isGreaterThan(0) ? sum.dividedBy(count) : new BigNumber(0);
247
+ return avgEntryPrice.toNumber();
248
+ }
249
+
250
+
251
+ async trackPositionHistory(address, contractId) {
252
+ const { openTrades, closeTrades } = await this.getCategorizedTrades(address, contractId);
253
+ //console.log('open trades for ' + address + ' ' + JSON.stringify(openTrades) + ' close trades ' + JSON.stringify(closeTrades));
254
+
255
+ // Sort open and close trades by block height
256
+ const sortedOpenTrades = openTrades.sort((a, b) => a.blockHeight - b.blockHeight);
257
+ const sortedCloseTrades = closeTrades.sort((a, b) => a.blockHeight - b.blockHeight);
258
+
259
+ // Break up opening trades based on consecutive closing trades
260
+ const separatedOpenTrades = this.breakUpOpeningTrades([...sortedOpenTrades], sortedCloseTrades);
261
+ //console.log('separatedOpenTrades ' + JSON.stringify(separatedOpenTrades));
262
+ const positionHistory = [];
263
+
264
+ for (const openTradesSubset of separatedOpenTrades) {
265
+ // Compute the average entry price for the current subset
266
+ const avgEntryPrice = this.computeAverageEntryPrices(openTradesSubset);
267
+ //console.log('avgEntryPrice for address ' + address + ' ' + avgEntryPrice);
268
+
269
+ let position = new BigNumber(0); // Reset position for each subset
270
+ let prevBlockHeight = 0;
271
+
272
+ openTradesSubset.forEach((trade) => {
273
+ const blockHeight = trade.block;
274
+
275
+ if (avgEntryPrice !== undefined) {
276
+ const entryPrice = avgEntryPrice;
277
+ const fullyClosesPosition = sortedCloseTrades.some(
278
+ (closeTrade) => closeTrade.block === blockHeight && closeTrade.fullyClosesPosition
279
+ );
280
+
281
+ // Check if it's a closing trade
282
+ if (fullyClosesPosition) {
283
+ // Calculate realized PNL for the closing trade
284
+ const pnl = entryPrice.minus(trade.price).times(trade.amount);
285
+ console.log('Realized PNL: ' + pnl.toNumber());
286
+
287
+ // Adjust position based on the closing trade
288
+ position = position.plus(pnl);
289
+ } else {
290
+ // It's an opening trade, update position accordingly
291
+ position = position.plus(trade.amount);
292
+ }
293
+
294
+ if (blockHeight !== prevBlockHeight) {
295
+ // If the block height changes, add a new entry to position history
296
+ positionHistory.push({
297
+ blockHeight,
298
+ position: position.toNumber(),
299
+ avgEntryPrice: entryPrice,
300
+ fullyClosesPosition,
301
+ });
302
+
303
+ // Reset the position for the new block height
304
+ position = new BigNumber(0);
305
+ }
306
+
307
+ if (!fullyClosesPosition) {
308
+ // Only update if the trade doesn't fully close the position
309
+ trade.position = position.toNumber();
310
+ }
311
+ }
312
+ })
313
+ }
314
+
315
+ return positionHistory;
316
+ }
317
+
318
+
319
+
320
+
321
+ breakUpOpeningTrades(openTrades, closeTrades) {
322
+ const separatedOpenTrades = [];
323
+ let currentBlockHeight = null;
324
+ let currentOpenTrades = [];
325
+ console.log('open and close trades in breakUpOpeningTrades ' + JSON.stringify(openTrades) + ' ' + JSON.stringify(closeTrades));
326
+
327
+ let closeTrade = null; // Initialize closeTrade
328
+
329
+ for (const trade of openTrades) {
330
+ const blockHeight = trade.blockHeight;
331
+
332
+ if (currentBlockHeight !== blockHeight) {
333
+ // Check for consecutive closing trades
334
+ if (closeTrade && closeTrade.blockHeight === blockHeight - 1) {
335
+ console.log('close trade blockHeight ' + closeTrade.blockHeight + ' ' + (blockHeight - 1));
336
+ }
337
+
338
+ const consecutiveCloses = closeTrades.filter(
339
+ close => close.blockHeight === blockHeight - 1
340
+ );
341
+
342
+ if (consecutiveCloses.length > 0) {
343
+ // Consecutive closing trade found, start a new array for open trades
344
+ separatedOpenTrades.push([...currentOpenTrades]);
345
+ currentOpenTrades = [];
346
+ }
347
+ }
348
+
349
+ currentOpenTrades.push(trade);
350
+ currentBlockHeight = blockHeight;
351
+ }
352
+
353
+ // Add the last set of open trades to the result array
354
+ separatedOpenTrades.push([...currentOpenTrades]);
355
+
356
+ return separatedOpenTrades;
357
+ }
358
+
359
+
360
+
361
+
362
+ async calculateLIFOEntry(address, amount, contractId) {
363
+ const categorizedTrades = await this.getCategorizedTrades(address, contractId);
364
+ console.log('open trades ' +JSON.stringify(categorizedTrades.openTrades));
365
+
366
+ // Sort trades by block height in descending order (LIFO)
367
+ categorizedTrades.openTrades.sort((a, b) => b.blockHeight - a.blockHeight);
368
+
369
+ // Calculate the LIFO entry based on the sorted trades
370
+ let remainingAmount = Math.abs(amount);
371
+ let totalCost = 0;
372
+ const blockTimes = [];
373
+
374
+ for (const trade of categorizedTrades.openTrades) {
375
+ const tradeAmount = Math.abs(trade.tradedAmount);
376
+ const tradeCost = tradeAmount * trade.price;
377
+ console.log('old open trade ' +JSON.stringify(trade)+ ' '+totalCost)
378
+ if (tradeAmount <= remainingAmount) {
379
+ // Fully cover the remaining amount with the current trade
380
+ totalCost += tradeCost;
381
+ remainingAmount -= tradeAmount;
382
+ blockTimes.push(trade.blockHeight); // Add block time of the closing trade
383
+ } else {
384
+ // Partially cover the remaining amount with the current trade
385
+ totalCost += (remainingAmount / tradeAmount) * tradeCost;
386
+ remainingAmount = 0;
387
+ blockTimes.push(trade.blockHeight); // Add block time of the closing trade
388
+ }
389
+
390
+ if (remainingAmount === 0) {
391
+ // Fully covered the given amount
392
+ break;
393
+ }
394
+ }
395
+
396
+ // Return an object with total cost and block times
397
+ return {
398
+ totalCost,
399
+ blockTimes,
400
+ };
401
+ }
402
+
403
+ /**
404
+ * Save PNL data to the trade history database.
405
+ *
406
+ * @param {number} currentBlockHeight - The current block height.
407
+ * @param {string} contractId - The contract ID associated with the trade.
408
+ * @param {number} accountingPNL - The accounting PNL value.
409
+ * @param {string} buyerAddress - The address of the buyer.
410
+ * @param {number} orderAmount - The amount in the buy order.
411
+ * @param {number} orderPrice - The price in the buy order.
412
+ * @param {string} collateralPropertyId - The ID of the collateral property.
413
+ * @param {string} timestamp - The timestamp of the trade.
414
+ * @param {string} buyerTx - The buyer's transaction ID.
415
+ * @param {number} settlementPNL - The settlement PNL value.
416
+ * @param {number} reduction - The reduction value.
417
+ * @param {object} LIFO - The LIFO data object.
418
+ * @returns {Promise<string>} - A Promise that resolves to the key under which the data is saved.
419
+ */
420
+ async savePNL(params) {
421
+ // Assuming tradeHistoryManager is an instance of a database manager or similar
422
+ // Adjust the following code based on your actual database handling implementation
423
+
424
+ // Assuming rPNL-address-contractId-block is the key structure you want to use
425
+ const key = `rPNL-${params.address}-${params.contractId}-${params.height}`;
426
+ console.log('preparing to save PNL '+JSON.stringify(params))
427
+
428
+ // Assuming tradeHistoryManager.save is a method to save data to the database
429
+ await this.save(key, params);
430
+
431
+ // Optionally, you can return the key or any other relevant information
432
+ return key;
433
+ }
434
+
435
+ /**
436
+ * Save data to the trade history database.
437
+ *
438
+ * @param {string} key - The key under which to save the data.
439
+ * @param {object} data - The data to be saved.
440
+ * @returns {Promise<void>} - A Promise that resolves once the data is saved.
441
+ */
442
+ async save(key, data) {
443
+ try {
444
+ const db = await dbInstance.getDatabase('tradeHistory');
445
+ const value = JSON.stringify(data);
446
+
447
+ console.log(`updating tradeHistoryDB with ${value}`);
448
+
449
+ // Save the data to the database
450
+ await db.updateAsync({ _id: key }, { $set: { value } }, { upsert: true });
451
+
452
+ console.log(`tradeHistoryDB saved successfully.`);
453
+ } catch (err) {
454
+ console.error(`Error saving tradeHistory rPNL:`, err);
455
+ throw err;
456
+ }
457
+ }
458
+
459
+ async displayPositionHistory(address, contractId) {
460
+ const positionHistory = this.getPositionHistoryForContract(address, contractId);
461
+ console.log(`Position History for Address ${address} and Contract ID ${contractId}:`);
462
+ console.table(positionHistory);
463
+ }
464
+
465
+ async saveTrade(tradeRecord) {
466
+ const tradeDB = await dbInstance.getDatabase('tradeHistory');
467
+
468
+ const uuid = uuidv4();
469
+
470
+ // Use the key provided in the trade record for storage
471
+ const tradeId = `${tradeRecord.key}-${uuid}-${tradeRecord.blockHeight}`;
472
+
473
+ // Construct the document to be saved
474
+ const tradeDoc = {
475
+ _id: tradeId,
476
+ ...tradeRecord
477
+ };
478
+
479
+ // Save or update the trade record in the database
480
+ try {
481
+ await tradeDB.updateAsync(
482
+ { _id: tradeId },
483
+ tradeDoc,
484
+ { upsert: true }
485
+ );
486
+ //console.log(`Trade record saved successfully: ${tradeId}`);
487
+ } catch (error) {
488
+ //console.error(`Error saving trade record: ${tradeId}`, error);
489
+ throw error; // Rethrow the error for handling upstream
490
+ }
491
+ }
492
+
493
+ // Returns trade history rows for a contract within [startBlock, endBlock] inclusive.
494
+ // This is a lightweight in-memory filter over loadTradeHistory(contractId),
495
+ // which already handles single-doc, legacy, and fallback formats.
496
+ static async getTradesForContractBetweenBlocks(contractId, startBlock, endBlock) {
497
+ const tradeDB = await dbInstance.getDatabase('tradeHistory');
498
+
499
+ const key = `contract-${contractId}`;
500
+
501
+ // Fast indexed-style query
502
+ const docs = await tradeDB.findAsync({
503
+ key,
504
+ blockHeight: { $gte: startBlock, $lte: endBlock }
505
+ });
506
+
507
+ if (!docs || !docs.length) return [];
508
+
509
+ return docs.map(d => d.trade ?? d);
510
+ }
511
+
512
+ async getFirstTradeBlock(contractId) {
513
+ const tradeDB = await dbInstance.getDatabase('tradeHistory');
514
+ const key = `contract-${contractId}`;
515
+
516
+ return new Promise((resolve, reject) => {
517
+ tradeDB.find(
518
+ { key, type: 'contract' },
519
+ { blockHeight: 1 }
520
+ )
521
+ .sort({ blockHeight: 1 })
522
+ .limit(1)
523
+ .exec((err, docs) => {
524
+ if (err) return reject(err);
525
+ if (!docs || docs.length === 0) return resolve(null);
526
+
527
+ resolve(docs[0].blockHeight);
528
+ });
529
+ })
530
+ }
531
+
532
+ // ------------------------------------------------------------------
533
+ // Return liquidation trades for a contract at an exact block height
534
+ // Authoritative source for liquidation-stage accounting
535
+ // ------------------------------------------------------------------
536
+ static async getLiquidationTradesForContractAtBlock(contractId, blockHeight) {
537
+ const trades = await this.getTradesForContractBetweenBlocks(
538
+ contractId,
539
+ blockHeight,
540
+ blockHeight
541
+ );
542
+ console.log('trades in get liq trades '+JSON.stringify(trades))
543
+ if (!trades || !trades.length) return [];
544
+
545
+ // Normalize + filter
546
+ return trades
547
+ .map(t => t.trade ?? t)
548
+ .filter(t => t && t.liquidation === true);
549
+ }
550
+ }
551
+
552
+ module.exports = TradeHistory;