Skip to content

Commit 530e16a

Browse files
committed
simulation selling service initial
Signed-off-by: MarcoMandar <malicemandar@gmail.com>
1 parent 1b6bfa2 commit 530e16a

File tree

2 files changed

+279
-0
lines changed

2 files changed

+279
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
import {
2+
TrustScoreDatabase,
3+
TokenPerformance,
4+
TradePerformance,
5+
TokenRecommendation,
6+
ProcessedTokenData,
7+
} from "@ai16z/plugin-trustdb";
8+
import { Connection, PublicKey } from "@solana/web3.js";
9+
// Assuming TokenProvider and IAgentRuntime are available
10+
import { TokenProvider } from "./token.ts";
11+
import { settings } from "@ai16z/eliza";
12+
import { IAgentRuntime, Memory, Provider, State } from "@ai16z/eliza";
13+
import { WalletProvider } from "./wallet.ts";
14+
15+
interface sellDetails {
16+
sell_amount: number;
17+
sell_recommender_id: string | null;
18+
}
19+
20+
export class simulationSellingService {
21+
private trustScoreDb: TrustScoreDatabase;
22+
private walletProvider: WalletProvider;
23+
private connection: Connection;
24+
private baseMint: PublicKey;
25+
private DECAY_RATE = 0.95;
26+
private MAX_DECAY_DAYS = 30;
27+
private backend: string;
28+
private backendToken: string;
29+
30+
constructor(
31+
runtime: IAgentRuntime,
32+
trustScoreDb: TrustScoreDatabase,
33+
walletProvider: WalletProvider
34+
) {
35+
this.trustScoreDb = trustScoreDb;
36+
37+
this.connection = new Connection(runtime.getSetting("RPC_URL"));
38+
this.walletProvider = new WalletProvider(
39+
this.connection,
40+
new PublicKey(runtime.getSetting("WALLET_PUBLIC_KEY"))
41+
);
42+
this.baseMint = new PublicKey(
43+
runtime.getSetting("BASE_MINT") ||
44+
"So11111111111111111111111111111111111111112"
45+
);
46+
this.backend = runtime.getSetting("BACKEND_URL");
47+
this.backendToken = runtime.getSetting("BACKEND_TOKEN");
48+
}
49+
50+
public async startService() {
51+
// starting the service
52+
console.log("Starting SellingService...");
53+
await this.scanAndSell();
54+
}
55+
56+
private async scanAndSell() {
57+
// scanning recommendations and selling
58+
console.log("Scanning for token performances...");
59+
const tokenPerformances =
60+
await this.trustScoreDb.getAllTokenPerformancesWithBalance();
61+
62+
const sellDecisions = this.decideWhenToSell(tokenPerformances);
63+
64+
// Execute sells
65+
await this.executeSells(sellDecisions);
66+
67+
// Perform stop loss checks
68+
await this.performStopLoss();
69+
}
70+
71+
private decideWhenToSell(
72+
tokenPerformances: TokenPerformance[]
73+
): SellDecision[] {
74+
// To Do: logic when to sell and how much
75+
console.log("Deciding when to sell and how much...");
76+
const decisions: SellDecision[] = [];
77+
78+
tokenPerformances.forEach((performance) => {
79+
const amountToSell = performance.balance * 0.1;
80+
decisions.push({ tokenPerformance: performance, amountToSell });
81+
});
82+
83+
return decisions;
84+
}
85+
86+
private async executeSells(decisions: SellDecision[]) {
87+
console.log("Executing sell orders...");
88+
for (const decision of decisions) {
89+
console.log(
90+
`Selling ${decision.amountToSell} of token ${decision.tokenPerformance.tokenSymbol}`
91+
);
92+
// To Do sell logic
93+
}
94+
}
95+
96+
private async performStopLoss() {
97+
console.log("Performing stop loss checks...");
98+
// To Do: Implement stop loss logic
99+
}
100+
101+
async updateSellDetails(
102+
tokenAddress: string,
103+
recommenderId: string,
104+
sellTimeStamp: string,
105+
sellDetails: sellDetails,
106+
isSimulation: boolean,
107+
tokenProvider: TokenProvider
108+
) {
109+
// To Do: Change the logic after codex update
110+
const recommender =
111+
await this.trustScoreDb.getOrCreateRecommenderWithTelegramId(
112+
recommenderId
113+
);
114+
const processedData: ProcessedTokenData =
115+
await tokenProvider.getProcessedTokenData();
116+
const prices = await this.walletProvider.fetchPrices(null);
117+
const solPrice = prices.solana.usd;
118+
const sellSol = sellDetails.sell_amount / parseFloat(solPrice);
119+
const sell_value_usd =
120+
sellDetails.sell_amount * processedData.tradeData.price;
121+
const trade = await this.trustScoreDb.getLatestTradePerformance(
122+
tokenAddress,
123+
recommender.id,
124+
isSimulation
125+
);
126+
const buyTimeStamp = trade.buy_timeStamp;
127+
const marketCap =
128+
processedData.dexScreenerData.pairs[0]?.marketCap || 0;
129+
const liquidity =
130+
processedData.dexScreenerData.pairs[0]?.liquidity.usd || 0;
131+
const sell_price = processedData.tradeData.price;
132+
const profit_usd = sell_value_usd - trade.buy_value_usd;
133+
const profit_percent = (profit_usd / trade.buy_value_usd) * 100;
134+
135+
const market_cap_change = marketCap - trade.buy_market_cap;
136+
const liquidity_change = liquidity - trade.buy_liquidity;
137+
138+
const isRapidDump = await this.isRapidDump(tokenAddress, tokenProvider);
139+
140+
const sellDetailsData = {
141+
sell_price: sell_price,
142+
sell_timeStamp: sellTimeStamp,
143+
sell_amount: sellDetails.sell_amount,
144+
received_sol: sellSol,
145+
sell_value_usd: sell_value_usd,
146+
profit_usd: profit_usd,
147+
profit_percent: profit_percent,
148+
sell_market_cap: marketCap,
149+
market_cap_change: market_cap_change,
150+
sell_liquidity: liquidity,
151+
liquidity_change: liquidity_change,
152+
rapidDump: isRapidDump,
153+
sell_recommender_id: sellDetails.sell_recommender_id || null,
154+
};
155+
this.trustScoreDb.updateTradePerformanceOnSell(
156+
tokenAddress,
157+
recommender.id,
158+
buyTimeStamp,
159+
sellDetailsData,
160+
isSimulation
161+
);
162+
163+
// If the trade is a simulation update the balance
164+
const oldBalance = this.trustScoreDb.getTokenBalance(tokenAddress);
165+
const tokenBalance = oldBalance - sellDetails.sell_amount;
166+
this.trustScoreDb.updateTokenBalance(tokenAddress, tokenBalance);
167+
// generate some random hash for simulations
168+
const hash = Math.random().toString(36).substring(7);
169+
const transaction = {
170+
tokenAddress: tokenAddress,
171+
type: "sell",
172+
transactionHash: hash,
173+
amount: sellDetails.sell_amount,
174+
price: processedData.tradeData.price,
175+
isSimulation: true,
176+
timestamp: new Date().toISOString(),
177+
};
178+
this.trustScoreDb.addTransaction(transaction);
179+
this.updateTradeInBe(
180+
tokenAddress,
181+
recommender.id,
182+
recommender.telegramId,
183+
sellDetailsData,
184+
tokenBalance
185+
);
186+
187+
return sellDetailsData;
188+
}
189+
async isRapidDump(
190+
tokenAddress: string,
191+
tokenProvider: TokenProvider
192+
): Promise<boolean> {
193+
const processedData: ProcessedTokenData =
194+
await tokenProvider.getProcessedTokenData();
195+
console.log(`Fetched processed token data for token: ${tokenAddress}`);
196+
197+
return processedData.tradeData.trade_24h_change_percent < -50;
198+
}
199+
200+
async delay(ms: number) {
201+
return new Promise((resolve) => setTimeout(resolve, ms));
202+
}
203+
204+
async updateTradeInBe(
205+
tokenAddress: string,
206+
recommenderId: string,
207+
username: string,
208+
data: sellDetails,
209+
balanceLeft: number,
210+
retries = 3,
211+
delayMs = 2000
212+
) {
213+
for (let attempt = 1; attempt <= retries; attempt++) {
214+
try {
215+
await fetch(
216+
`${this.backend}/api/updaters/updateTradePerformance`,
217+
{
218+
method: "POST",
219+
headers: {
220+
"Content-Type": "application/json",
221+
Authorization: `Bearer ${this.backendToken}`,
222+
},
223+
body: JSON.stringify({
224+
tokenAddress: tokenAddress,
225+
tradeData: data,
226+
recommenderId: recommenderId,
227+
username: username,
228+
isSimulation: true,
229+
balanceLeft: balanceLeft,
230+
}),
231+
}
232+
);
233+
// If the request is successful, exit the loop
234+
return;
235+
} catch (error) {
236+
console.error(
237+
`Attempt ${attempt} failed: Error creating trade in backend`,
238+
error
239+
);
240+
if (attempt < retries) {
241+
console.log(`Retrying in ${delayMs} ms...`);
242+
await this.delay(delayMs); // Wait for the specified delay before retrying
243+
} else {
244+
console.error("All attempts failed.");
245+
}
246+
}
247+
}
248+
}
249+
}
250+
251+
// SellDecision interface
252+
interface SellDecision {
253+
tokenPerformance: TokenPerformance;
254+
amountToSell: number;
255+
}

packages/plugin-trustdb/src/adapters/trustScoreDatabase.ts

+24
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,30 @@ export class TrustScoreDatabase {
827827
};
828828
}
829829

830+
getAllTokenPerformancesWithBalance(): TokenPerformance[] {
831+
const sql = `SELECT * FROM token_performance WHERE balance > 0;`;
832+
const rows = this.db.prepare(sql).all() as TokenPerformanceRow[];
833+
834+
return rows.map((row) => ({
835+
tokenAddress: row.token_address,
836+
priceChange24h: row.price_change_24h,
837+
volumeChange24h: row.volume_change_24h,
838+
trade_24h_change: row.trade_24h_change,
839+
liquidity: row.liquidity,
840+
liquidityChange24h: row.liquidity_change_24h,
841+
holderChange24h: row.holder_change_24h,
842+
rugPull: row.rug_pull === 1,
843+
isScam: row.is_scam === 1,
844+
marketCapChange24h: row.market_cap_change24h,
845+
sustainedGrowth: row.sustained_growth === 1,
846+
rapidDump: row.rapid_dump === 1,
847+
suspiciousVolume: row.suspicious_volume === 1,
848+
validationTrust: row.validation_trust,
849+
balance: row.balance,
850+
lastUpdated: new Date(row.last_updated),
851+
}));
852+
}
853+
830854
// ----- TokenRecommendations Methods -----
831855

832856
/**

0 commit comments

Comments
 (0)