@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.
- package/.claude/settings.local.json +13 -0
- package/.claude/skills/tl-algo/SKILL.md +255 -0
- package/.gitattributes +2 -0
- package/.github/workflows/publish.yaml +26 -0
- package/4mm.js +163 -0
- package/LICENSE +21 -0
- package/NPMSwapRefactor.zip +0 -0
- package/README.md +217 -0
- package/address.sh +26 -0
- package/algoAPI.js +581 -0
- package/analyzepsbt.js +92 -0
- package/apiEx.js +99 -0
- package/bb_hyperscalper.js +290 -0
- package/bbo_demo.js +111 -0
- package/buyer.js +622 -0
- package/client.js +50 -0
- package/createTxTest.js +26 -0
- package/createWallet.js +75 -0
- package/daytrader.js +531 -0
- package/decodeTest.js +69 -0
- package/fundingManager.js +144 -0
- package/index.js +4 -0
- package/listener.js +27 -0
- package/litecoreTxBuilder.js +1128 -0
- package/mmEx.js +356 -0
- package/networks.js +51 -0
- package/orderbook.js +200 -0
- package/package.json +34 -0
- package/perTradeQueue.js +36 -0
- package/projectsTLNPMTLNPM/package-lock.json +162 -0
- package/projectsTLNPMTLNPM/package.json +5 -0
- package/quick.js +32 -0
- package/quickFut.js +37 -0
- package/quickSell.js +37 -0
- package/relayerClient.js +117 -0
- package/run4mm.js +80 -0
- package/run_bbo_tracker.js +241 -0
- package/seller.js +443 -0
- package/session.js +45 -0
- package/setup-lin-ltc.sh +139 -0
- package/setup-lin.sh +203 -0
- package/setup-win-ltc.bat +108 -0
- package/setup-win.bat +167 -0
- package/spam_screamer_futures.js +222 -0
- package/tradelayer.js/.gitattributes +2 -0
- package/tradelayer.js/README.md +2 -0
- package/tradelayer.js/oldTests/activationTest.js +6 -0
- package/tradelayer.js/oldTests/base58.test.js +23 -0
- package/tradelayer.js/oldTests/base64Decode.test.js +16 -0
- package/tradelayer.js/oldTests/blocksRefactor.js +140 -0
- package/tradelayer.js/oldTests/checkVestBalance.js +25 -0
- package/tradelayer.js/oldTests/consensusHashProto.js +151 -0
- package/tradelayer.js/oldTests/contractOrderbook.js +243 -0
- package/tradelayer.js/oldTests/createPayload.js +0 -0
- package/tradelayer.js/oldTests/createTestnetAddr.js +43 -0
- package/tradelayer.js/oldTests/decode.js +205 -0
- package/tradelayer.js/oldTests/decodeTest.js +50 -0
- package/tradelayer.js/oldTests/displayTallyMap.js +19 -0
- package/tradelayer.js/oldTests/encodeDecode.js +340 -0
- package/tradelayer.js/oldTests/expressTest.js +29 -0
- package/tradelayer.js/oldTests/extractBlocksVanilla.js +214 -0
- package/tradelayer.js/oldTests/extractBlocksVanillaa.js +179 -0
- package/tradelayer.js/oldTests/extractPubkeyTest.js +60 -0
- package/tradelayer.js/oldTests/fillInputCacheProto.js +111 -0
- package/tradelayer.js/oldTests/getRawTxTest.js +22 -0
- package/tradelayer.js/oldTests/indexTest.js +26 -0
- package/tradelayer.js/oldTests/initTokensTest.js +32 -0
- package/tradelayer.js/oldTests/interfaceChild.js +129 -0
- package/tradelayer.js/oldTests/listenerChild.js +112 -0
- package/tradelayer.js/oldTests/opdecode.js +26 -0
- package/tradelayer.js/oldTests/options.js +79 -0
- package/tradelayer.js/oldTests/optxtest.js +116 -0
- package/tradelayer.js/oldTests/optxtest1.js +64 -0
- package/tradelayer.js/oldTests/oracle.test.js +32 -0
- package/tradelayer.js/oldTests/orderbook.test.js +36 -0
- package/tradelayer.js/oldTests/parsing.js +93 -0
- package/tradelayer.js/oldTests/payload.js +13 -0
- package/tradelayer.js/oldTests/persistenceUnitTest.js +23 -0
- package/tradelayer.js/oldTests/property.test.js +53 -0
- package/tradelayer.js/oldTests/propertyLevel.js +75 -0
- package/tradelayer.js/oldTests/propertyTest.js +32 -0
- package/tradelayer.js/oldTests/queryAddressTest.js +17 -0
- package/tradelayer.js/oldTests/salter.js +14 -0
- package/tradelayer.js/oldTests/tally.js +81 -0
- package/tradelayer.js/oldTests/tally.test.js +48 -0
- package/tradelayer.js/oldTests/tally2.js +124 -0
- package/tradelayer.js/oldTests/tally3.js +142 -0
- package/tradelayer.js/oldTests/tallyDiag.js +38 -0
- package/tradelayer.js/oldTests/testGetRaw.js +40 -0
- package/tradelayer.js/oldTests/testHexConvert.js +47 -0
- package/tradelayer.js/oldTests/testNewEncoding.js +96 -0
- package/tradelayer.js/oldTests/testNewEncoding2.js +113 -0
- package/tradelayer.js/oldTests/testNewEncoding3 +112 -0
- package/tradelayer.js/oldTests/testNewEncoding3.js +168 -0
- package/tradelayer.js/oldTests/testOPReturn.js +102 -0
- package/tradelayer.js/oldTests/testPayload.js +23 -0
- package/tradelayer.js/oldTests/testRaw.js +50 -0
- package/tradelayer.js/oldTests/testSendTooMuch.js +20 -0
- package/tradelayer.js/oldTests/testTxBuild +28 -0
- package/tradelayer.js/oldTests/testTxBuild.js +42 -0
- package/tradelayer.js/oldTests/tokenOrderbook.js +243 -0
- package/tradelayer.js/oldTests/txUtilsA.js +515 -0
- package/tradelayer.js/oldTests/validityUnitTest.js +53 -0
- package/tradelayer.js/oldTests/vaults.js +72 -0
- package/tradelayer.js/oldTests/volumeIndex.js +117 -0
- package/tradelayer.js/oldTests/volumeIndex2.js +88 -0
- package/tradelayer.js/output_base64.txt +1 -0
- package/tradelayer.js/package-lock.json +9967 -0
- package/tradelayer.js/package.json +61 -0
- package/tradelayer.js/server/index.js +88 -0
- package/tradelayer.js/server/litecoind.exe +0 -0
- package/tradelayer.js/src/activation.js +303 -0
- package/tradelayer.js/src/adjuster.js +77 -0
- package/tradelayer.js/src/amm.js +400 -0
- package/tradelayer.js/src/base256.js +55 -0
- package/tradelayer.js/src/base94.js +79 -0
- package/tradelayer.js/src/channels.js +1163 -0
- package/tradelayer.js/src/clearing.js +3109 -0
- package/tradelayer.js/src/clearlist.js +364 -0
- package/tradelayer.js/src/client.js +295 -0
- package/tradelayer.js/src/consensus.js +613 -0
- package/tradelayer.js/src/contractRegistry.js +964 -0
- package/tradelayer.js/src/db.js +89 -0
- package/tradelayer.js/src/init.js +24 -0
- package/tradelayer.js/src/insurance.js +347 -0
- package/tradelayer.js/src/interface.js +218 -0
- package/tradelayer.js/src/interfaceExpress.js +178 -0
- package/tradelayer.js/src/iou.js +509 -0
- package/tradelayer.js/src/listener.js +226 -0
- package/tradelayer.js/src/logic.js +1702 -0
- package/tradelayer.js/src/main.js +927 -0
- package/tradelayer.js/src/marginMap.js +2165 -0
- package/tradelayer.js/src/options.js +126 -0
- package/tradelayer.js/src/oracle.js +394 -0
- package/tradelayer.js/src/orderbook.js +4123 -0
- package/tradelayer.js/src/persistence.js +554 -0
- package/tradelayer.js/src/property.js +411 -0
- package/tradelayer.js/src/reOrg.js +41 -0
- package/tradelayer.js/src/scaling.js +145 -0
- package/tradelayer.js/src/tally.js +1275 -0
- package/tradelayer.js/src/tradeHistoryManager.js +552 -0
- package/tradelayer.js/src/txDecoder.js +584 -0
- package/tradelayer.js/src/txEncoder.js +610 -0
- package/tradelayer.js/src/txIndex.js +502 -0
- package/tradelayer.js/src/txUtils.js +1392 -0
- package/tradelayer.js/src/types.js +429 -0
- package/tradelayer.js/src/validity.js +3077 -0
- package/tradelayer.js/src/vaults.js +430 -0
- package/tradelayer.js/src/vesting.js +491 -0
- package/tradelayer.js/src/volumeIndex.js +618 -0
- package/tradelayer.js/src/walletInterface.js +220 -0
- package/tradelayer.js/src/walletListener.js +665 -0
- package/tradelayer.js/tests/256decode.js +82 -0
- package/tradelayer.js/tests/UTXOracle.js +205 -0
- package/tradelayer.js/tests/base94test.js +23 -0
- package/tradelayer.js/tests/cancelTxTest.js +62 -0
- package/tradelayer.js/tests/contractInterfaceTest.js +48 -0
- package/tradelayer.js/tests/decimalTest.js +65 -0
- package/tradelayer.js/tests/decoderTest.js +100 -0
- package/tradelayer.js/tests/deltaCount.js +47 -0
- package/tradelayer.js/tests/deltaCount2.js +60 -0
- package/tradelayer.js/tests/interfaceTest.js +37 -0
- package/tradelayer.js/tests/mainTest.js +53 -0
- package/tradelayer.js/tests/makeActivationTest.js +24 -0
- package/tradelayer.js/tests/maxHeightTest.js +49 -0
- package/tradelayer.js/tests/reverseHash.js +72 -0
- package/tradelayer.js/tests/sensitiveConsoleOutput.txt +267 -0
- package/tradelayer.js/tests/tallyTest.js +40 -0
- package/tradelayer.js/tests/testBuybacks.js +46 -0
- package/tradelayer.js/tests/testCodeHash.js +49 -0
- package/tradelayer.js/tests/testConsensusHash.js +91 -0
- package/tradelayer.js/tests/testDecode.js +30 -0
- package/tradelayer.js/tests/testEncodingLengths.js +129 -0
- package/tradelayer.js/tests/testGetTx +32 -0
- package/tradelayer.js/tests/testGetTx.js +32 -0
- package/tradelayer.js/tests/testHexHash.js +32 -0
- package/tradelayer.js/tests/testIndexHash.js +35 -0
- package/tradelayer.js/tests/testInitContracts.js +38 -0
- package/tradelayer.js/tests/testMaxConsensus.js +12 -0
- package/tradelayer.js/tests/testMaxSynth.js +44 -0
- package/tradelayer.js/tests/testMint.js +21 -0
- package/tradelayer.js/tests/testNetwork.js +33 -0
- package/tradelayer.js/tests/testOrderbookLoad.js +62 -0
- package/tradelayer.js/tests/testRebates.js +32 -0
- package/tradelayer.js/tests/testRedeem.js +22 -0
- package/tradelayer.js/tests/testTokenTrade.js +39 -0
- package/tradelayer.js/tests/testTxBuild.js +42 -0
- package/tradelayer.js/tests/testUTXOTrade.js +27 -0
- package/tradelayer.js/tests/tokenTradeHistory.js +27 -0
- package/tradelayer.js/tests/tradeFutures.js +40 -0
- package/tradelayer.js/tests/tradeHistoryExample.js +35 -0
- package/tradelayer.js/tests/tradeHistoryLoad.js +15 -0
- package/tradelayer.js/tests/txScanTest.js +134 -0
- package/tradelayer.js/tests/validateTest.js +136 -0
- package/tradelayer.js/tests/vestingTest.js +37 -0
- package/tradelayer.js/utils/activateMainnet.js +59 -0
- package/tradelayer.js/utils/activateMainnetDoge.js +63 -0
- package/tradelayer.js/utils/autocompactdb.js +23 -0
- package/tradelayer.js/utils/base64toHex.js +32 -0
- package/tradelayer.js/utils/broadcastDoge.js +38 -0
- package/tradelayer.js/utils/calcRedeem.js +19 -0
- package/tradelayer.js/utils/checkNetwork.js +27 -0
- package/tradelayer.js/utils/createAddress.js +48 -0
- package/tradelayer.js/utils/createAttestation.js +133 -0
- package/tradelayer.js/utils/createContract.js +118 -0
- package/tradelayer.js/utils/createOracle.js +94 -0
- package/tradelayer.js/utils/createwallet.js +20 -0
- package/tradelayer.js/utils/crossFuturesTrades.js +57 -0
- package/tradelayer.js/utils/crossTokenTrades.js +62 -0
- package/tradelayer.js/utils/dumpPriv.js +29 -0
- package/tradelayer.js/utils/generateChannel.js +34 -0
- package/tradelayer.js/utils/getInfo.js +21 -0
- package/tradelayer.js/utils/hardWipe.js +20 -0
- package/tradelayer.js/utils/hexTo64.js +16 -0
- package/tradelayer.js/utils/importAddress.js +28 -0
- package/tradelayer.js/utils/importpriv.js +20 -0
- package/tradelayer.js/utils/issueOracleContract.js +67 -0
- package/tradelayer.js/utils/issueTokens.js +41 -0
- package/tradelayer.js/utils/listunspent.js +66 -0
- package/tradelayer.js/utils/litecoinClient.js +30 -0
- package/tradelayer.js/utils/loadwallet.js +20 -0
- package/tradelayer.js/utils/publishOracle.js +113 -0
- package/tradelayer.js/utils/sendActivation.js +21 -0
- package/tradelayer.js/utils/sendChannelContractTrade.js +34 -0
- package/tradelayer.js/utils/sendChannelTokenTrade.js +34 -0
- package/tradelayer.js/utils/sendCommit.js +24 -0
- package/tradelayer.js/utils/sendDoge.js +62 -0
- package/tradelayer.js/utils/sendDogeMain.js +67 -0
- package/tradelayer.js/utils/sendDogeTx.js +46 -0
- package/tradelayer.js/utils/sendLTC.js +63 -0
- package/tradelayer.js/utils/sendMainnet.js +62 -0
- package/tradelayer.js/utils/sendTransfer.js +19 -0
- package/tradelayer.js/utils/sendVestTest.js +88 -0
- package/tradelayer.js/utils/sendWithdrawal.js +26 -0
- package/tradelayer.js/utils/simpleStart.js +8 -0
- package/tradelayer.js/utils/startStop.js +27 -0
- package/tradelayer.js/utils/structuredTrades.js +136 -0
- package/tradelayer.js/utils/verifySignature.js +90 -0
- package/tradelayer.js/utils/verifyWitnessAndScriptPubkey.js +41 -0
- package/tradelayer.js/utils/walletCache.js +172 -0
- package/tradelayer.js/utils/walletContractInterface.js +48 -0
- package/tradelayer.js/utils/walletFetchTxs.js +66 -0
- package/tradelayer.js/utils/walletUtils.js +97 -0
- package/tradelayer.js/utils/wipeDB.js +55 -0
- package/tradelayer.js/utils/wipeDBNotTx.js +50 -0
- package/txEncoder.js +529 -0
- package/utility.js +28 -0
- package/verifymessage.js +38 -0
- 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&¤tTrade.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)&¤tTrade.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&¤tTrade.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)&¤tTrade.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;
|