-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtrade_analyze.html
228 lines (209 loc) · 11.4 KB
/
trade_analyze.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Trade Analyze</title>
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
font-family: Arial, sans-serif;
background-color: #f8f9fa;
padding: 20px;
}
#txList {
max-height: 300px;
overflow-y: auto;
border: 1px solid #ccc;
padding: 10px;
margin-top: 10px;
white-space: pre-wrap;
background: #ffffff;
font-size: 13px;
}
#output {
font-size: 15px;
}
#status {
margin-top: 10px;
color: green;
}
.token-info span {
font-size: 14px;
font-weight: normal;
color: #666;
}
</style>
</head>
<body>
<div class="container">
<h1 class="text-center my-3">币种交易分析器 v1.0</h1>
<div class="d-grid gap-2">
<button class="btn btn-primary" onclick="connectWallet()">连接 OKX Web3 钱包</button>
</div>
<div class="mt-3">
<label class="form-label" for="addressInput">钱包地址:</label>
<input type="text" id="addressInput" class="form-control" placeholder="输入钱包地址">
</div>
<div class="mt-3">
<label class="form-label" for="mbcContractInput">Token合约地址:</label>
<input type="text" id="mbcContractInput" class="form-control" value="0x7D28276933D6aA0Ef1513F8B5e18dC492befeFea">
</div>
<div class="mt-3">
<label class="form-label" for="usdtContractInput">USDT 合约地址:</label>
<input type="text" id="usdtContractInput" class="form-control" value="0x55d398326f99059fF775485246999027B3197955">
</div>
<div class="mt-3">
<label class="form-label" for="pairContractInput">Token-USDT交易对合约地址:</label>
<input type="text" id="pairContractInput" class="form-control" value="0x2d7c6794ef5a5234b26ba620c659c0913f4b0609">
</div>
<div class="d-grid gap-2 mt-3">
<button class="btn btn-success" onclick="analyzeTrades()">开始分析</button>
</div>
<div id="status" class="mt-3"></div>
<div class="card mt-3">
<div class="card-body token-info">
<h5>币名: <span id="tokenName"></span></h5>
<h6>流通总量: <span id="tokenSupply"></span></h6>
<h6>精度: <span id="tokenDecimals"></span></h6>
</div>
</div>
<pre id="output" class="mt-3 p-2 bg-light border"></pre>
<div id="txList" class="mt-3 p-2 bg-white border"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<script>
const API_KEY = "KIUQKQCQH7F3JZ9IS3SSYRV6DK2TU6B4WP";
async function connectWallet() {
if (typeof window.okxwallet === 'undefined') {
alert("请先安装 OKX Web3 钱包扩展");
return;
}
try {
const accounts = await window.okxwallet.request({ method: 'eth_requestAccounts' });
const address = accounts[0];
document.getElementById("addressInput").value = address;
document.getElementById("status").textContent = `✅ 已连接 OKX 钱包:${address}`;
analyzeTrades();
} catch (err) {
console.error("连接失败:", err);
document.getElementById("status").textContent = `❌ 连接失败: ${err.message}`;
}
}
async function getTokenNameAndSupply(contractAddress) {
const API_URL = `https://api.bscscan.com/api?module=stats&action=tokenCsupply&contractaddress=${contractAddress}&apikey=${API_KEY}`;
const nameUrl = `https://api.bscscan.com/api?module=token&action=tokeninfo&contractaddress=${contractAddress}&apikey=${API_KEY}`;
const [supplyRes, nameRes] = await Promise.all([fetch(API_URL), fetch(nameUrl)]);
const supplyData = await supplyRes.json();
const nameData = await nameRes.json();
let tokenName = nameData.result ? nameData.result.tokenName || "未知币种" : "未知币种";
if (document.getElementById("mbcContractInput").value.trim() === '0x7D28276933D6aA0Ef1513F8B5e18dC492befeFea'){
tokenName = 'MBC';
}
const tokenDecimal = nameData.result ? parseInt(nameData.result.decimals || "18") : 18;
const rawSupply = supplyData.result || "0";
const formattedSupply = (parseFloat(rawSupply) / Math.pow(10, tokenDecimal)).toLocaleString();
return {
name: tokenName,
totalSupply: formattedSupply,
decimals: tokenDecimal
};
}
async function getTransactions(address) {
const API_URL = `https://api.bscscan.com/api?module=account&action=tokentx&address=${address}&startblock=0&endblock=99999999&sort=asc&apikey=${API_KEY}`;
const res = await fetch(API_URL);
const data = await res.json();
return data.result || [];
}
async function getLatestMbcPrice() {
const DEXSCREENER_URL = "https://api.dexscreener.com/latest/dex/pairs/bsc/0x2d7c6794ef5a5234b26ba620c659c0913f4b0609";
const res = await fetch(DEXSCREENER_URL);
const data = await res.json();
if (data && data.pair && data.pair.priceUsd) {
return parseFloat(data.pair.priceUsd);
}
return -1;
}
async function analyzeTrades() {
const MBC_CONTRACT = document.getElementById("mbcContractInput").value.trim();
const BSC_USD_CONTRACT = document.getElementById("usdtContractInput").value.trim();
const PAIR_CONTRACT = document.getElementById("pairContractInput").value.trim();
const ADDRESS = document.getElementById("addressInput").value.trim();
if (!ADDRESS) {
document.getElementById("status").textContent = "❗ 请先连接钱包或输入钱包地址。";
return;
}
document.getElementById("status").textContent = "正在分析,请稍候...";
try {
const { name: tokenName, totalSupply, decimals } = await getTokenNameAndSupply(MBC_CONTRACT);
document.getElementById("tokenName").textContent = tokenName;
document.getElementById("tokenSupply").textContent = totalSupply;
document.getElementById("tokenDecimals").textContent = decimals;
const transactions = await getTransactions(ADDRESS);
const latestPrice = await getLatestMbcPrice();
let totalBuyCost = 0, totalBuyQuantity = 0;
let totalSellRevenue = 0, totalSellQuantity = 0;
let holdingQuantity = 0, buyCount = 0, sellCount = 0;
let realizedProfit = 0;
let txDetails = [];
for (let tx of transactions) {
const value = parseInt(tx.value) / Math.pow(10, parseInt(tx.tokenDecimal));
const time = new Date(parseInt(tx.timeStamp) * 1000).toLocaleString();
if (tx.contractAddress.toLowerCase() === MBC_CONTRACT.toLowerCase()) {
if (tx.to.toLowerCase() === ADDRESS.toLowerCase()) {
const correspondingTx = transactions.find(t => t.hash === tx.hash && t.contractAddress.toLowerCase() === BSC_USD_CONTRACT.toLowerCase());
if (correspondingTx) {
const cost = parseInt(correspondingTx.value) / Math.pow(10, parseInt(correspondingTx.tokenDecimal));
const price = cost / value;
totalBuyCost += cost;
totalBuyQuantity += value;
holdingQuantity += value;
buyCount++;
txDetails.push(`🟢 买入 ${value.toFixed(2)} ${tokenName},成本 $${cost.toFixed(2)},单价 $${price.toFixed(4)}\n时间: ${time}\n哈希: ${tx.hash}`);
}
} else if (tx.from.toLowerCase() === ADDRESS.toLowerCase()) {
const correspondingTx = transactions.find(t => t.hash === tx.hash && t.contractAddress.toLowerCase() === BSC_USD_CONTRACT.toLowerCase());
if (correspondingTx) {
const revenue = parseInt(correspondingTx.value) / Math.pow(10, parseInt(correspondingTx.tokenDecimal));
const price = revenue / value;
totalSellRevenue += revenue;
totalSellQuantity += value;
holdingQuantity -= value;
sellCount++;
realizedProfit += (price * value) - ((totalBuyCost / totalBuyQuantity) * value);
txDetails.push(`🔴 卖出 ${value.toFixed(2)} ${tokenName},收入 $${revenue.toFixed(2)},单价 $${price.toFixed(4)}\n时间: ${time}\n哈希: ${tx.hash}`);
}
}
}
}
const avgBuyPrice = totalBuyQuantity ? (totalBuyCost / totalBuyQuantity).toFixed(4) : 0;
const avgSellPrice = totalSellQuantity ? (totalSellRevenue / totalSellQuantity).toFixed(4) : 0;
const pnl = (totalSellRevenue - totalBuyCost).toFixed(1);
const unrealizedPnl = (holdingQuantity * latestPrice).toFixed(1);
const currentAvgPrice = holdingQuantity ? (totalBuyCost / holdingQuantity).toFixed(4) : 0;
const unrealizedProfit = latestPrice !== -1 ? (holdingQuantity * latestPrice - totalBuyCost).toFixed(1) : 0;
const result = {
"当前币种单价": latestPrice,
"平均买入价": avgBuyPrice,
"平均卖出价": avgSellPrice,
"买入次数": buyCount,
"卖出次数": sellCount,
"持有数量": holdingQuantity,
"当前均价": currentAvgPrice,
"总盈亏": pnl,
"已实现利润": realizedProfit.toFixed(1),
"未实现估值": unrealizedPnl,
"未实现利润": unrealizedProfit,
};
document.getElementById("output").textContent = JSON.stringify(result, null, 4);
document.getElementById("txList").textContent = txDetails.length ? txDetails.join("\n\n") : "没有找到相关交易记录。";
document.getElementById("status").textContent = "✅ 分析完成。";
} catch (error) {
document.getElementById("status").textContent = `❌ 分析失败:${error.message}`;
document.getElementById("output").textContent = "";
document.getElementById("txList").textContent = "";
}
}
</script>
</body>
</html>