From cf7f58a8dd0154342a41e91c0c132f4c8df0ed64 Mon Sep 17 00:00:00 2001 From: konard Date: Sat, 11 Apr 2026 18:14:45 +0000 Subject: [PATCH 1/3] Initial commit with task details Adding .gitkeep for PR creation (default mode). This file will be removed when the task is complete. Issue: https://github.com/xlabtg/teleton-plugins/issues/133 --- .gitkeep | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitkeep b/.gitkeep index 79a620e..65e8825 100644 --- a/.gitkeep +++ b/.gitkeep @@ -1,4 +1,5 @@ # .gitkeep file auto-generated at 2026-03-19T10:37:13.073Z for PR creation at branch issue-19-f54b585823d1 for issue https://github.com/xlabtg/teleton-plugins/issues/19 # Updated: 2026-03-27T01:04:44.761Z # Updated: 2026-04-05T19:20:26.278Z -# Updated: 2026-04-09T18:02:32.277Z \ No newline at end of file +# Updated: 2026-04-09T18:02:32.277Z +# Updated: 2026-04-11T18:14:44.989Z \ No newline at end of file From 4297872f5459d39303a4bb8ee3d636c16ad6618e Mon Sep 17 00:00:00 2001 From: konard Date: Sat, 11 Apr 2026 18:27:44 +0000 Subject: [PATCH 2/3] fix(ton-trading-bot): use exit_price to convert USD P&L to TON (issue #133) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The simulation balance credit-back in ton_trading_record_trade was dividing the USD P&L by the entry price (USD/TON at trade open) to convert it back to TON, instead of using the exit price (current market rate at trade close). When TON appreciates significantly (e.g. +10.6% from $1.26 → $1.393), this caused the simulation balance to be over-credited: - Buggy (entry price $1.26): pnl $1.995 / $1.26 = +1.583 TON profit - Correct (exit price $1.393): pnl $1.995 / $1.393 = +1.432 TON profit ✓ The fix: use exit_price_usd (falling back to entry_price_usd when not provided) so the USD profit is converted to TON at the current exchange rate. Includes a new regression test for the exact scenario from issue #133 (15 TON trade, $1.26 → $1.393) and updates two existing tests whose expected balance values were based on the wrong (entry-price) formula. Co-Authored-By: Claude Sonnet 4.6 --- plugins/ton-trading-bot/index.js | 12 ++-- plugins/ton-trading-bot/manifest.json | 2 +- plugins/ton-trading-bot/tests/index.test.js | 78 +++++++++++++++++++-- 3 files changed, 81 insertions(+), 11 deletions(-) diff --git a/plugins/ton-trading-bot/index.js b/plugins/ton-trading-bot/index.js index 1ad0a47..2e4bafc 100644 --- a/plugins/ton-trading-bot/index.js +++ b/plugins/ton-trading-bot/index.js @@ -631,14 +631,16 @@ export const tools = (sdk) => [ // If simulation trade was opened with TON, credit back principal + profit/loss in TON. // The balance was decremented by amount_in (TON) on open; on close we restore it. // When USD prices are available the pnl is in USD — convert back to TON using - // the entry price (USD price of TON at trade open). When no prices were provided - // (same-asset TON→TON trade) the raw amount_out is already in TON. + // the exit price (USD price of TON at trade close). Using the exit price correctly + // reflects how much TON the USD profit buys at the current market rate. + // Example: pnl=$1.995 at exit $1.393/TON → 1.432 TON added (not 1.583 with entry $1.26). + // When no prices were provided (same-asset TON→TON trade) the raw amount_out is in TON. if (entry.mode === "simulation" && entry.from_asset === "TON") { const simBalance = getSimBalance(sdk); - const entryTonPriceUsd = entry.entry_price_usd ?? null; + const exitTonPriceUsd = exit_price_usd ?? entry.entry_price_usd ?? null; const creditTon = - entryTonPriceUsd != null - ? entry.amount_in + pnl / entryTonPriceUsd + exitTonPriceUsd != null + ? entry.amount_in + pnl / exitTonPriceUsd : amount_out; // same-currency (TON→TON): just return what came out setSimBalance(sdk, simBalance + creditTon); } diff --git a/plugins/ton-trading-bot/manifest.json b/plugins/ton-trading-bot/manifest.json index f0653a4..3287a56 100644 --- a/plugins/ton-trading-bot/manifest.json +++ b/plugins/ton-trading-bot/manifest.json @@ -1,7 +1,7 @@ { "id": "ton-trading-bot", "name": "TON Trading Bot", - "version": "2.0.0", + "version": "2.0.1", "description": "Atomic TON trading tools: market data, portfolio, risk validation, simulation, DEX swap execution, cross-DEX arbitrage, sniper trading, copy trading, liquidity pools, farming, backtesting, risk management, and automation.", "author": { "name": "xlabtg", diff --git a/plugins/ton-trading-bot/tests/index.test.js b/plugins/ton-trading-bot/tests/index.test.js index 302d8b8..f3a4aee 100644 --- a/plugins/ton-trading-bot/tests/index.test.js +++ b/plugins/ton-trading-bot/tests/index.test.js @@ -1537,7 +1537,7 @@ describe("ton-trading-bot plugin", () => { // 13 TON → USDT trade; entry_price_usd=1.33 (TON at open), exit_price_usd=1.34 (TON rose slightly) // Both prices refer to from_asset (TON) per the corrected semantics. // pnl_usd = amount_in * (exit_price - entry_price) = 13 * (1.34 - 1.33) = 13 * 0.01 = 0.13 USD - // credit_ton = amount_in + pnl_usd / entry_price_usd = 13 + 0.13/1.33 ≈ 13.098 + // credit_ton = amount_in + pnl_usd / exit_price_usd = 13 + 0.13/1.34 ≈ 13.097 const openTrade = { id: 100, mode: "simulation", @@ -1575,7 +1575,7 @@ describe("ton-trading-bot plugin", () => { ); assert.equal(result.success, true); assert.ok(savedBalance !== null, "simulation balance should be updated on close"); - // Expected: 50 (prev balance) + 13 (principal) + 0.13/1.33 ≈ 63.098 + // Expected: 50 (prev balance) + 13 (principal) + 0.13/1.34 ≈ 63.097 assert.ok(savedBalance > 63, `balance should be restored to ~63+, got ${savedBalance}`); assert.ok(savedBalance < 64, `balance should be around 63, got ${savedBalance}`); }); @@ -1663,7 +1663,7 @@ describe("ton-trading-bot plugin", () => { // 10 TON → USDT at $2/TON (entry), TON dropped to $1.5 at exit → loss // exit_price_usd = 1.5 (TON exit price, from_asset price at close) // usdOut = 10 * 1.5 = 15, usdIn = 10 * 2 = 20, pnl = -5 USD - // credit_ton = 10 + (-5/2) = 10 - 2.5 = 7.5 TON + // credit_ton = 10 + (-5/1.5) = 10 - 3.333 = 6.667 TON (uses exit_price for conversion) const openTrade = { id: 103, mode: "simulation", @@ -1701,8 +1701,76 @@ describe("ton-trading-bot plugin", () => { ); assert.equal(result.success, true); assert.equal(result.data.profit_or_loss, "loss"); - // credit_ton = 7.5, new balance = 90 + 7.5 = 97.5 - assert.ok(Math.abs(savedBalance - 97.5) < 0.0001, `expected 97.5, got ${savedBalance}`); + // credit_ton = 10 + (-5/1.5) = 10 - 3.333 = 6.667, new balance = 90 + 6.667 = 96.667 + const expectedBalance = 90 + 10 + (-5 / 1.5); // 96.667 + assert.ok(Math.abs(savedBalance - expectedBalance) < 0.0001, `expected ${expectedBalance}, got ${savedBalance}`); + }); + + it("credits back correct profit for large price move (issue #133): uses exit_price not entry_price", async () => { + // Issue #133: 15 TON trade at entry $1.26, TON rises to $1.393 (+10.6%) + // Expected profit in sim balance: ~1.43 TON (pnl converted at exit price) + // Buggy behaviour: used entry_price for conversion → profit = 1.583 TON (over-credited by 10.6%) + // + // pnl_usd = 15 * (1.393 - 1.26) = 15 * 0.133 = 1.995 USD + // credit_ton (correct, exit price): 15 + 1.995/1.393 = 16.432 TON → profit = 1.432 TON ≈ 1.43 + // credit_ton (buggy, entry price): 15 + 1.995/1.26 = 16.583 TON → profit = 1.583 TON (too high) + const openTrade = { + id: 133, + mode: "simulation", + from_asset: "TON", + to_asset: "EQUsdtAddress", + amount_in: 15, + entry_price_usd: 1.26, + amount_out: null, + status: "open", + }; + let savedBalance = null; + const sdk = { + ...makeSdk({ dbRows: { trade: openTrade, simBalance: { balance: 1000 } } }), + db: { + exec: () => {}, + prepare: (sql) => ({ + get: () => { + if (sql.includes("sim_balance")) return { balance: 1000 }; + if (sql.includes("trade_journal") && sql.includes("WHERE id")) return openTrade; + return null; + }, + all: () => [], + run: (...args) => { + if (sql.includes("INSERT INTO sim_balance")) savedBalance = args[1]; + return { lastInsertRowid: 1 }; + }, + }), + }, + log: { info: () => {}, warn: () => {}, error: () => {}, debug: () => {} }, + }; + const tool = mod.tools(sdk).find((t) => t.name === "ton_trading_record_trade"); + const result = await tool.execute( + { trade_id: 133, amount_out: 20.895, exit_price_usd: 1.393 }, + makeContext() + ); + assert.equal(result.success, true); + // pnl = 15 * 1.393 - 15 * 1.26 = 1.995 USD + assert.ok(Math.abs(result.data.pnl - 1.995) < 0.001, `pnl should be ~1.995, got ${result.data.pnl}`); + + // Correct: credit uses exit_price ($1.393) → balance = 1000 + 15 + 1.995/1.393 = 1016.432 + const pnlUsd = 15 * (1.393 - 1.26); + const expectedCredit = 15 + pnlUsd / 1.393; // = 16.432 (uses exit price) + const buggyCredit = 15 + pnlUsd / 1.26; // = 16.583 (uses entry price — old bug) + const expectedBalance = 1000 + expectedCredit; // = 1016.432 + const expectedProfit = expectedCredit - 15; // = 1.432 TON ≈ expected "~1.43 TON" + + assert.ok(savedBalance !== null, "simulation balance should be updated on close"); + assert.ok( + Math.abs(savedBalance - expectedBalance) < 0.001, + `balance should be ~${expectedBalance.toFixed(3)} (profit ~${expectedProfit.toFixed(3)} TON), got ${savedBalance}` + ); + // Verify it is NOT the over-credited (buggy) value + const buggyBalance = 1000 + buggyCredit; + assert.ok( + Math.abs(savedBalance - buggyBalance) > 0.05, + `balance must NOT be the over-credited buggy value ~${buggyBalance.toFixed(3)}, got ${savedBalance}` + ); }); }); From 5a85c532b7a6d545ec4973d18cc4ccd98f68fc49 Mon Sep 17 00:00:00 2001 From: konard Date: Sat, 11 Apr 2026 18:32:05 +0000 Subject: [PATCH 3/3] Revert "Initial commit with task details" This reverts commit cf7f58a8dd0154342a41e91c0c132f4c8df0ed64. --- .gitkeep | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitkeep b/.gitkeep index 65e8825..79a620e 100644 --- a/.gitkeep +++ b/.gitkeep @@ -1,5 +1,4 @@ # .gitkeep file auto-generated at 2026-03-19T10:37:13.073Z for PR creation at branch issue-19-f54b585823d1 for issue https://github.com/xlabtg/teleton-plugins/issues/19 # Updated: 2026-03-27T01:04:44.761Z # Updated: 2026-04-05T19:20:26.278Z -# Updated: 2026-04-09T18:02:32.277Z -# Updated: 2026-04-11T18:14:44.989Z \ No newline at end of file +# Updated: 2026-04-09T18:02:32.277Z \ No newline at end of file