本文介绍了如何使用 QuickNode Webhooks 构建一个 BNB 链上的 Memecoin 复制交易机器人,该机器人通过监控成功交易者的链上交易,并实时执行类似的交易。文章详细介绍了如何设置 QuickNode Webhooks,构建 JavaScript 过滤器,以及实现基于 Viem 的交易逻辑,包括交易规模调整、滑点保护和风险管理等。
Copytrading 允许你通过监控成功交易者的链上交易并实时执行类似的交易,从而自动镜像他们的交易。在本指南中,你将构建一个 copytrading 机器人,该机器人监控 four.meme 平台(BNB Chain 流行的 memecoin LaunchPad)上的代币购买行为,并在你的目标钱包进行购买时自动执行成比例的交易。
通过利用 QuickNode 的 Webhooks,你将收到链上事件的即时通知,使你的机器人能够在被追踪钱包交易的几秒钟内做出反应。
TokenPurchase 事件免责声明
本指南仅用于教育目的。加密货币交易具有重大风险,并且 copytrading 不能保证盈利。成功交易者过去的表现并不代表未来的结果。始终进行自己的研究,并且只用你能承受损失的资金进行交易。自动化交易机器人可能会发生故障或被利用,可能导致资金损失。
在构建机器人之前,必须了解 four.meme 平台的工作原理以及我们可以从其智能合约事件中提取哪些数据。
该平台使用类似于 Solana 的 Pump.fun 的 bonding curve 机制。当用户在该平台上创建代币时:
主合约 TokenManager2 部署在 BNB Chain 主网上的 0x5c952063c7fc8610FFDB798152D69F0B9550762b。虽然该合约会发出多个事件,但我们将重点关注 TokenPurchase 事件,以跟踪用户购买并触发我们的 copytrading 逻辑。
当用户在该平台上购买代币时,该合约会发出一个 TokenPurchase 事件,其结构如下:
event TokenPurchase(
address token,
address account,
uint256 price,
uint256 amount,
uint256 cost,
uint256 fee,
uint256 offers,
uint256 funds
);
TokenPurchase(address,address,uint256,uint256,uint256,uint256,uint256,uint256) 的事件签名哈希为 0x7db52723a3b2cdd6164364b3b766e65e540d7be48ffa89582956d8eaebe62942,我们用它来过滤 TokenPurchase 事件。
有关合约和事件结构的更多详细信息,请参见 four.meme 协议集成指南。
索引参数与非索引参数
重要提示:这些参数均未被索引,这意味着它们都出现在事件的 data 字段中,而不是作为单独的 topics。这需要手动解码数据字段才能提取各个值。
在以太坊和 EVM 兼容区块链中,事件参数可以是 indexed 或 non-indexed。索引参数存储在事件日志的 topics 数组中,从而可以进行高效的过滤和搜索。非索引参数存储在 data 字段中,需要解码才能访问其值。
事件的非索引参数以单个十六进制字符串的形式位于事件日志的 data 字段中。要提取各个参数,我们需要根据 ABI 规范解码此数据。
以下是 TokenPurchase 事件的示例事件日志的一部分。在它下面,我们分解了如何解码 data 字段。
TokenPurchase 事件日志示例
{
"address": "0x5c952063c7fc8610ffdb798152d69f0b9550762b",
"topics": [\
"0x7db52723a3b2cdd6164364b3b766e65e540d7be48ffa89582956d8eaebe62942" // 事件签名哈希\
],
"data": "0x00000000000000000000000076138888158f7ce4bbe14c59e18e880d57ab44440000000000000000000000004262f7b70b81538258eb2c5ecad3947ba4e0c8b0000000000000000000000000000000000000000000000000000000029c13f53700000000000000000000000000000000000000000003a339d3d41d9ad2a4520000000000000000000000000000000000000000000000000000ae1e3ecafdee3e0000000000000000000000000000000000000000000000000001bdbe1163d1be000000000000000000000000000000000000000001991941ab911ad2ead4940000000000000000000000000000000000000000000000000021ff7f07b91232ea",
// ...
}
数据字段的分解
00000000000000000000000076138888158f7ce4bbe14c59e18e880d57ab4444 // 64 个十六进制字符 (bytes32/uint256 - 零填充地址 - token)
0000000000000000000000004262f7b70b81538258eb2c5ecad3947ba4e0c8b0 // 64 个十六进制字符 (bytes32/uint256 - 零填充地址 - buyer)
000000000000000000000000000000000000000000000000000000029c13f537 // 64 个十六进制字符 (uint256 - price)
00000000000000000000000000000000000000000003a339d3d41d9ad2a45200 // 64 个十六进制字符 (uint256 - amount)
00000000000000000000000000000000000000000000000000ae1e3ecafdee3e // 64 个十六进制字符 (uint256 - cost)
0000000000000000000000000000000000000000000000000001bdbe1163d1be // 64 个十六进制字符 (uint256 - fee)
000000000000000000000000000000000000000001991941ab911ad2ead49400 // 64 个十六进制字符 (uint256 - offers)
0000000000000000000000000000000000000000000000000021ff7f07b91232ea // 64 个十六进制字符 (uint256 - funds)
因此,要解码 data 字段,我们将其拆分为 8 个 32 字节(64 个十六进制字符)的段,分别对应于 TokenPurchase 事件的 8 个参数。 然后,我们使用参数类型来确定数据类型并相应地对其进行解码。
现在我们了解了事件结构以及如何对其进行解码,我们可以继续学习如何使用 QuickNode Webhooks 过滤这些事件。
QuickNode Webhooks 允许你在将区块链事件传递到你的终端节点之前,先在服务器端对其进行过滤。 通过仅发送相关事件,这样可以节省带宽和成本。
QuickNode Webhooks UI 允许轻松创建简单的过滤器,但是对于像我们这样的更复杂的场景,我们需要解码非索引事件数据并按多个参数进行过滤,因此我们可以使用自定义 JavaScript 过滤器。
为了监视来自 four.meme 合约的 TokenPurchase 事件,我们将创建一个自定义 JavaScript 过滤器,该过滤器:
TokenPurchase 事件data 字段中提取购买者地址下面的过滤器函数实现了上述逻辑。 它处理每个区块的回执,过滤相关日志,解码 TokenPurchase 事件参数,并返回针对我们的 copytrading 机器人优化的结构化负载。
在深入研究代码之前,让我们分解一下逻辑:
合约地址匹配:我们将合约地址规范化为小写,以避免区分大小写的比较。
事件签名匹配:我们使用事件签名哈希来过滤 TokenPurchase 事件。 这确保了我们仅处理相关事件。
数据提取:由于 TokenPurchase 参数未被索引,因此我们手动解析 data 字段。 每个参数占用 32 个字节(64 个十六进制字符)。 地址已填充,因此我们跳过前 24 个十六进制字符(12 个字节)以提取 20 字节的地址。 extractAddress 和 extractUint256 辅助函数处理此问题。
偏移量计算:参数位置从零开始索引:
token 地址。buyer 地址(我们的过滤器目标)。price、amount、cost、fee、offers、funds。成本优化:为不匹配的区块返回 null 可以防止不必要的数据传输。 QuickNode 仅对已传递的负载收费,因此在服务器端进行过滤具有成本效益。
查看 JavaScript 过滤器代码
four.meme TokenPurchase 过滤器
function main(payload) {
const { data, metadata } = payload;
// Configuration constants
const TARGET_WALLET = "YOUR_TARGET_WALLET_ADDRESS_HERE"; // 👈 REPLACE WITH YOUR TARGET WALLET ADDRESS
const TARGET_CONTRACT = "0x5c952063c7fc8610FFDB798152D69F0B9550762b";
const TOKEN_PURCHASE_SIG =
"0x7db52723a3b2cdd6164364b3b766e65e540d7be48ffa89582956d8eaebe62942";
// Normalize for comparison
const normalizedContract = TARGET_CONTRACT.toLowerCase();
const normalizedWallet = TARGET_WALLET.toLowerCase();
const copyTrades = [];
// Helper function to extract address from data field at given offset
function extractAddress(dataHex, offset) {
const data = dataHex.slice(2);
// Each parameter is 32 bytes (64 hex chars)
// Address is 20 bytes, padded with 12 bytes of zeros on the left
const start = offset * 64 + 24; // Skip 24 hex chars (12 bytes) of padding
const addressHex = data.slice(start, start + 40);
return "0x" + addressHex.toLowerCase();
}
// Helper function to extract uint256 from data field at given offset
function extractUint256(dataHex, offset) {
const data = dataHex.slice(2);
const start = offset * 64;
const uint256Hex = data.slice(start, start + 64);
// Return as hex string with 0x prefix (can be converted to BigInt if needed)
return "0x" + uint256Hex;
}
// Helper function to convert hex to decimal string (for readability)
function hexToDecimal(hexString) {
try {
// Remove 0x prefix if present
const hex = hexString.startsWith("0x") ? hexString.slice(2) : hexString;
// Convert to BigInt to handle large numbers
return BigInt("0x" + hex).toString();
} catch (error) {
return hexString; // Return original if conversion fails
}
}
// Process all receipts in the block
data[0].receipts.forEach((receipt) => {
// Filter logs matching the contract and event signature
const relevantLogs = receipt.logs.filter((log) => {
if (
!log.address ||
log.address.toLowerCase() !== normalizedContract ||
!log.topics ||
log.topics[0] !== TOKEN_PURCHASE_SIG ||
!log.data
) {
return false;
}
// Extract buyer address from data field (2nd parameter, offset 1)
try {
const buyerAddress = extractAddress(log.data, 1);
return buyerAddress === normalizedWallet;
} catch (error) {
// Skip malformed logs
return false;
}
});
if (relevantLogs.length > 0) {
// Decode all parameters for each relevant log
const decodedLogs = relevantLogs.map((log) => {
try {
// Extract all 8 parameters
const token = extractAddress(log.data, 0);
const buyer = extractAddress(log.data, 1);
const price = extractUint256(log.data, 2);
const amount = extractUint256(log.data, 3);
const cost = extractUint256(log.data, 4);
const fee = extractUint256(log.data, 5);
const offers = extractUint256(log.data, 6);
const funds = extractUint256(log.data, 7);
return {
token: token,
buyer: buyer,
price: hexToDecimal(price),
amount: hexToDecimal(amount), // Human-readable decimal
cost: hexToDecimal(cost),
fee: hexToDecimal(fee),
offers: hexToDecimal(offers),
funds: hexToDecimal(funds),
};
} catch (error) {
return {
error: "Failed to decode log",
errorMessage: error.message,
rawData: log.data,
};
}
});
copyTrades.push({
transactionHash: receipt.transactionHash,
blockNumber: receipt.blockNumber,
blockTimestamp: parseInt(data[0].block.timestamp, 16),
buyer: TARGET_WALLET,
contract: TARGET_CONTRACT,
from: receipt.from,
to: receipt.to,
logs: decodedLogs,
status: receipt.status,
});
}
});
// Return null for no matches (saves bandwidth and costs)
if (copyTrades.length === 0) {
return null;
}
// Return structured payload optimized for trading bot
return {
trades: copyTrades,
};
}
此过滤器返回的负载将发送到我们的 webhook 服务器,该服务器将处理交易并使用 Viem 执行它们。 以下是来自 TokenPurchase 事件的示例负载:
查看 QuickNode Webhook 负载
QuickNode Webhook 负载示例
{
"trades": [\
{\
"blockNumber": "0x3e5cecb",\
"blockTimestamp": 1761045030,\
"buyer": "0x4262F7B70b81538258EB2C5ECAD3947Ba4e0C8b0",\
"contract": "0x5c952063c7fc8610FFDB798152D69F0B9550762b",\
"from": "0x4262f7b70b81538258eb2c5ecad3947ba4e0c8b0",\
"logs": [\
{\
"amount": "4397589923821429000000000",\
"buyer": "0x4262f7b70b81538258eb2c5ecad3947ba4e0c8b0",\
"fee": "490099009900990",\
"funds": "2449816393459315434",\
"offers": "494569930785511810000000000",\
"price": "11208488247",\
"token": "0x76138888158f7ce4bbe14c59e18e880d57ab4444",\
"cost": "49009900990099006"\
}\
],\
"status": "0x1",\
"to": "0x1de460f363af910f51726def188f9004276bf4bc",\
"transactionHash": "0x4f4e720a02e9523a7637426f64982552a791ab55d63b5849466826dd20289523"\
}\
]
}
我们将在下一节中使用过滤功能来设置 QuickNode Webhooks。 目前,我们将继续创建一个 webhook 服务器来接收负载并根据该负载实现 copytrading 逻辑。
在开始编写代码之前,让我们回顾一下项目结构和关键组件。 如果你想跳过,请随时跳到 Copytrading 机器人项目设置 部分。
├── src/
│ ├── config.ts # 配置和环境变量
│ ├── webhookServer.ts # 用于接收 webhook 的 Express 服务器
│ ├── tradingBot.ts # 基于 Viem 的交易逻辑
│ └── index.ts # 入口点
├── .env.example # 环境变量模板
└── package.json # Node.js 项目文件
config.ts 文件包含机器人的配置和环境变量。 它导入 dotenv 包以从 .env 文件加载环境变量。
Webhook 服务器处理来自 QuickNode 的传入通知以及用于安全性的 HMAC 签名验证。 它通过从 tradingBot.ts 调用 executeCopyTrade 函数来处理负载并触发交易逻辑。
来自 webhookServer.ts 的代码段
/**
* 用于接收交易通知的 Webhook 终端节点
*/
app.post("/webhook", async (req: Request, res: Response) => {
try {
// 提取安全标头
const nonce = req.headers["x-qn-nonce"] as string;
const timestamp = req.headers["x-qn-timestamp"] as string;
const signature = req.headers["x-qn-signature"] as string;
// 获取负载
const payload =
typeof req.body === "string" ? req.body : JSON.stringify(req.body);
// 验证 HMAC 签名
if (
config.quicknodeSecurityToken &&
!verifyHMAC(payload, nonce, timestamp, signature)
) {
console.error("❌ HMAC verification failed");
return res.status(401).json({ error: "Invalid signature" });
}
// 解析负载
const data = typeof req.body === "string" ? JSON.parse(req.body) : req.body;
// 立即响应以防止重试
res.status(200).json({ status: "received" });
// 异步处理交易
if (data.trades && data.trades.length > 0) {
console.log(`\n${"=".repeat(60)}`);
console.log(`🚨 New Webhook Received - ${new Date().toISOString()}`);
console.log(`${"=".repeat(60)}`);
for (const trade of data.trades) {
await executeCopyTrade(trade);
}
}
} catch (error: any) {
console.error("❌ Webhook processing error:", error.message);
}
});
executeCopyTrade 函数包含核心交易逻辑。 它会根据配置的乘数计算复制交易规模,检查钱包余额,应用滑点容差,并使用 Viem 执行交易。
交易规模调整:机器人使用 COPY_TRADE_MULTIPLIER 按比例计算交易规模。 例如,如果一条鲸鱼使用 0.1 BNB 进行购买,而你的乘数为 0.1 (10%),则你将交易 0.01 BNB。
安全限制:
滑点保护:机器人会根据鲸鱼的价格和你配置的滑点容差来计算 minAmount。 如果价格超出此阈值而不利地变动,则交易将回滚,从而保护你免受抢跑攻击或快速价格变动的影响。
交易模拟:在 writeContract 之前使用 simulateContract 可以捕获潜在的错误(资金不足、合约回滚),而不会消耗 gas 费。 这是所有生产机器人的最佳实践。
four.meme 合约具有多个 buyTokenAMAP 重载。 我们使用 4 参数版本:
function buyTokenAMAP(
uint256 origin, // 推荐/来源代码(直接使用 0)
address token, // 要购买的代币地址
uint256 funds, // 要花费的 BNB 金额(以 wei 为单位)
uint256 minAmount // 要接收的最小代币数量(滑点保护)
) external payable
函数参数:
0。value 参数匹配expectedTokens * (100 - slippage%) / 100该函数是 payable,因此你必须通过与 funds 参数匹配的 value 参数发送 BNB。
以下是 tradingBot.ts 中的代码段,演示了复制交易执行逻辑:
来自 tradingBot.ts 的代码段
const tradeData = payload.logs[0]; // 第一个日志条目
const whaleCostBNB = parseFloat(formatEther(BigInt(tradeData.cost)));
const whaleFee = parseFloat(formatEther(BigInt(tradeData.fee)));
// 策略:仅当鲸鱼大量购买时才复制
if (whaleCostBNB < config.minCopyTradeAmount) {
console.log(
`⏭️ Skipping - Trade too small (< ${config.minCopyTradeAmount} BNB)`
);
return;
}
// 计算我们的交易金额(例如,鲸鱼交易的 10%)
let ourTradeAmount = whaleCostBNB * config.copyTradeMultiplier;
// 应用安全限制
if (ourTradeAmount > config.maxTradeAmount) {
console.log(
`⚠️ Capping trade at max limit: ${config.maxTradeAmount} BNB`
);
ourTradeAmount = config.maxTradeAmount;
}
// 检查钱包余额
const balance = await client.getBalance({ address: account.address });
const balanceBNB = parseFloat(formatEther(balance));
console.log(`\n💰 Wallet Balance: ${balanceBNB.toFixed(6)} BNB`);
if (balanceBNB < ourTradeAmount + config.minBalance) {
console.log(
`❌ Insufficient balance (need ${
ourTradeAmount + config.minBalance
} BNB including reserve)`
);
return;
}
// 使用滑点容差计算 minAmount
// 根据鲸鱼的费率估算预期代币
const expectedAmount =
(BigInt(tradeData.amount) * parseEther(ourTradeAmount.toString())) /
BigInt(tradeData.cost);
const minAmount =
(expectedAmount * BigInt(100 - config.slippageTolerance)) / BigInt(100);
// 执行交易
const { request } = await client.simulateContract({
account: account,
address: config.contractAddress,
abi: TRADING_ABI,
functionName: "buyTokenAMAP",
args: [\
BigInt(0), // origin\
tradeData.token, // 代币地址\
parseEther(ourTradeAmount.toString()), // BNB 金额(以 wei 为单位)\
minAmount, // 要接收的最小代币数量\
],
value: parseEther(ourTradeAmount.toString()),
});
const txHash = await client.writeContract(request);
console.log(`✅ Transaction sent: ${txHash}`);
console.log(`🔍 View on BscScan: https://bscscan.com/tx/${txHash}`);
// 等待确认
const receipt = await client.waitForTransactionReceipt({
hash: txHash,
});
现在,让我们设置项目和依赖项。
若要按照本指南进行操作,请确保你具有:
https://example.bnb.quiknode.pro/abc123/)TARGET_WALLET 更新为你想要监视的地址(例如,0x4262F7B70b81538258EB2C5ECAD3947Ba4e0C8b0)65392331)注意:设置目标 URL 和创建 webhook 将在你设置公共 URL 之后完成,我们将在下一节中介绍。 因此,暂时将其保留在此处。 稍后我们将回到它。
Webhook 安全Token
QuickNode Webhooks 提供了一个安全Token来验证传入的请求。 虽然它是可选的,但强烈建议使用它,以确保只有来自 QuickNode 的合法请求才能由你的 webhook 服务器处理。 有关更多详细信息,请参见 如何验证传入的 Streams Webhook 消息 ( Streams & Webhooks 使用相同的 HMAC 方案)。
我们将使用我们的 QuickNode 指南示例 存储库来轻松设置 copytrading 机器人。 克隆该存储库并导航到 webhooks/copytrading-bot-bnb 目录。
git clone https://github.com/quiknode-labs/qn-guide-examples.git
cd qn-guide-examples/webhooks/copytrading-bot-bnb
使用你选择的包管理器(npm、yarn、pnpm 等)安装所需的依赖项。
npm install
## or
yarn install
## or
pnpm install
主要依赖项:
将 .env.example 文件复制到 .env。
cp .env.example .env
然后,使用你的凭据编辑 .env:
## 区块链配置
BNB_RPC_URL=你的-quicknode-rpc-url # 👈 在此处更新
## 钱包配置(⚠️ 保持安全)
PRIVATE_KEY=你的-私钥 # 👈 在此处更新
## Webhook 安全
QUICKNODE_SECURITY_TOKEN=你的-安全Token # 👈 在此处更新
## 服务器配置
PORT=3000
## 交易策略
MIN_COPY_TRADE_AMOUNT=0.01 # 仅复制 >= 0.01 BNB 的交易
COPY_TRADE_MULTIPLIER=0.01 # 复制鲸鱼交易规模的 0.01 (1%)
MAX_TRADE_AMOUNT=0.5 # 每次交易最多 0.5 BNB
MIN_BALANCE=0.0001 # 为 gas 保留 0.0001 BNB
SLIPPAGE_TOLERANCE=5 # 5% 的滑点容差
安全注意事项
切勿将你的 .env 文件提交到版本控制。 .gitignore 文件已将其排除。
使用以下命令运行机器人:
npm run dev
预期输出:
🔑 交易钱包:0x...
💰 当前余额:0.523456 BNB
============================================================
🚀 BNB Chain Copytrading 机器人已启动
============================================================
📡 Webhook URL: http://localhost:3000/webhook
💚 健康检查:http://localhost:30001. 返回到你之前离开的 QuickNode Webhooks 仪表板。
2. 将 **Destination URL** 设置为你的公共 webhook URL(例如,`https://abc123.ngrok.io/webhook`)。
3. 通过向 webhook 终端发送测试 payload 来测试 webhook。
4. 如果一切正常,并且测试区块有一个合适的 `TokenPurchase` 事件,你应该会看到你的 bot 基于测试数据执行跟单交易。
5. 创建你的 webhook。
#### 监控 Bot 活动
现在,当你的目标钱包进行购买时,该 bot 将收到 webhooks。你将看到如下输出:
📊 Whale Trade Detected: ├─ Token: 0x76138888158f7ce4bbe14c59e18e880d57ab4444 ├─ Whale: 0x4262F7B70b81538258EB2C5ECAD3947Ba4e0C8b0 ├─ Amount: 4397.589924 tokens ├─ Cost: 0.000049 BNB ├─ Fee: 0.000000 BNB ├─ Total Spent: 0.000049 BNB └─ TX: 0x4f4e720a...
💰 Wallet Balance: 0.523456 BNB
🎯 Executing Copy Trade: ├─ Our Amount: 0.000005 BNB ├─ Expected Tokens: 439.758992 ├─ Min Tokens: 417.870842 └─ Slippage: 5%
⏳ Sending transaction... ✅ Transaction sent: 0x789abc... 🔍 View on BscScan: https://bscscan.com/tx/0x789abc... ✅ Copy trade successful! Block: 45678901
恭喜!你已使用 QuickNode Webhooks 和 Viem 在 BNB Chain 上成功构建了一个 memecoin 跟单交易 bot。
### 结论
你已经构建了一个功能性的跟单交易 bot,它使用 QuickNode Webhooks 实时监控 BNB Chain 的交易,并使用 Viem 执行自动化交易。该 bot 演示了关键的区块链开发概念:事件过滤、webhook 处理、安全交易签名和智能交易执行。
QuickNode 的 Webhooks 产品提供了对时间敏感型交易应用程序所需的可靠、低延迟的基础设施。通过在服务器端过滤事件并仅传递相关交易,你可以最大限度地降低带宽成本并最大限度地提高响应能力。
此处实施的跟单交易策略可作为更复杂的交易系统的基础。随着你使用上面建议的改进来扩展 bot 的功能,你将更深入地了解链上交易动态并开发出更完善的自动化策略。
订阅我们的[新闻通讯](https://go.quicknode.com/newsletter),获取更多 Web3 开发指南和区块链教程。如果你有疑问或需要帮助,请加入我们的 [Discord 社区](https://discord.gg/quicknode) 或使用下面的表格提供反馈。在 [X](https://x.com/QuickNode) (@QuickNode) 和 [Telegram](https://t.me/quicknodehq) 上关注我们,获取最新更新。
#### 进一步改进
一旦你拥有一个可用的跟单交易 bot,请考虑以下增强功能:
> [QuickNode Marketplace](https://www.quicknode.com/marketplace) 上提供了各种各样的市场插件和服务,可以帮助你轻松实现其中的一些功能。
##### 高级交易功能
**基于波动率的动态滑点**:根据最近的价格波动调整滑点容忍度。在高波动时期,增加滑点以提高执行率,同时保持可接受的价格影响。
**多钱包监控**:同时跟踪多个成功的交易者。实施加权复制,根据不同钱包的历史表现为其分配不同的百分比。
**基于胜率的仓位大小**:跟踪每个鲸鱼(whale)的成功率并相应地调整你的复制百分比。成功的交易者会获得更高的乘数,而表现不佳的钱包则会减少或被淘汰。
##### 市场情报
**美元价格整合**:将所有 BNB 金额转换为美元。这有助于你设置一致的基于美元的限额,而不管 BNB 的价格波动如何。
**盈亏跟踪**:将交易历史记录保存在数据库(例如,PostgreSQL 或 MongoDB)中,以计算已实现和未实现的损益。使用此数据来监控绩效指标,例如胜率、每笔交易的平均利润以及整体投资回报率 (ROI)。
##### 性能优化
**Gas 价格优化**:监控 BNB Chain 的 gas 价格并相应地调整你的交易。在高拥堵期间,你可能需要提高 gas 价格以加快执行速度,或者暂停跟单交易以避免过高的成本。
**MEV 保护**:与支持 BNB Chain 的私有交易中继集成,以防止对你的复制交易进行三明治攻击(sandwich attacks)。
##### 风险管理
**止损机制**:自动出售跌破一定百分比阈值的仓位。这会限制下行空间,同时让赢家继续盈利。
**仓位限制**:限制所有代币的总风险敞口。例如,永远不要将超过 50% 的资金用于活跃的 memecoin 仓位。
**黑名单/白名单**:维护要避免(已知的 rug、honeypots)或首选(经过验证的项目、高流动性)的代币列表。根据链上分析或社区报告更新这些列表。
##### 我们 ❤️ 反馈!
如果你有任何反馈或对新主题的请求,请[告诉我们](https://airtable.com/shrKKKP7O1Uw3ZcUB?prefill_Guide+Name=Build%20a%20Memecoin%20Copytrading%20Bot%20on%20BNB%20Chain)。我们很乐意听取你的意见。
>- 原文链接: [quicknode.com/guides/qui...](https://www.quicknode.com/guides/quicknode-products/webhooks/copytrading-bot-with-webhooks)
>- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~ 如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!