DEV Community

deni yuda
deni yuda

Posted on

How To Build Pump.fun / Pump swap copy sniper bot (6)

Practice

Update real time token metrix about bought token

 /// Update metrics for a token based on parsed transaction data
    pub async fn update_metrics(&self, token_mint: &str, parsed_data: &ParsedData) -> Result<()> {
        let logger = Logger::new("[SELLING-STRATEGY] => ".magenta().to_string());

        // Extract data
        let sol_change = parsed_data.sol_change;
        let token_change = parsed_data.token_change;
        let is_buy = parsed_data.is_buy;
        let timestamp = parsed_data.timestamp.unwrap_or_else(|| {
            std::time::SystemTime::now()
                .duration_since(std::time::UNIX_EPOCH)
                .unwrap_or_default()
                .as_secs()
        });

        // Get wallet pubkey
        let wallet_pubkey = self.app_state.wallet.try_pubkey()
            .map_err(|e| anyhow!("Failed to get wallet pubkey: {}", e))?;

        // Get token account to determine actual balance
        let token_pubkey = Pubkey::from_str(token_mint)
            .map_err(|e| anyhow!("Invalid token mint address: {}", e))?;
        let ata = get_associated_token_address(&wallet_pubkey, &token_pubkey);

        // Get current token balance
        let actual_token_balance = match self.app_state.rpc_nonblocking_client.get_token_account(&ata).await {
            Ok(Some(account)) => {
                let amount_value = account.token_amount.amount.parse::<f64>()
                    .map_err(|e| anyhow!("Failed to parse token amount: {}", e))?;
                amount_value / 10f64.powi(account.token_amount.decimals as i32)
            },
            Ok(None) => 0.0,
            Err(_) => 0.0,
        };

        // Calculate price if possible
        let price = if token_change != 0.0 && sol_change != 0.0 {
            (sol_change / token_change).abs()
        } else {
            0.0
        };

        if price <= 0.0 {
            logger.log(format!("Invalid price calculated: {}", price));
            return Err(anyhow!("Invalid price calculation"));
        }

        // Update token metrics using entry API
        let mut entry = TOKEN_METRICS.entry(token_mint.to_string()).or_insert_with(|| TokenMetrics {
            entry_price: 0.0,
            highest_price: 0.0,
            lowest_price: 0.0,
            current_price: 0.0,
            volume_24h: 0.0,
            market_cap: 0.0,
            time_held: 0,
            last_update: Instant::now(),
            buy_timestamp: timestamp,
            amount_held: 0.0,
            cost_basis: 0.0,
            price_history: VecDeque::new(),
            volume_history: VecDeque::new(),
            liquidity_at_entry: 0.0,
        });

        // Update metrics based on transaction type
        if is_buy {
            // For buys, update entry price using weighted average
            let token_amount = token_change.abs();
            let sol_amount = sol_change.abs();

            if token_amount > 0.0 {
                // Calculate new weighted average entry price
                let new_entry_price = if entry.amount_held > 0.0 {
                    // Weighted average of existing position and new purchase
                    ((entry.entry_price * entry.amount_held) + (price * token_amount)) 
                    / (entry.amount_held + token_amount)
                } else {
                    // First purchase
                    price
                };

                // Update entry price and cost basis
                entry.entry_price = new_entry_price;
                entry.cost_basis += sol_amount;

                logger.log(format!(
                    "Updated entry price for buy: old={}, new={} (weighted avg)", 
                    entry.entry_price, new_entry_price
                ));
            }
        } else {
            // For sells, adjust cost basis proportionally but keep entry price
            if entry.amount_held > 0.0 && entry.cost_basis > 0.0 {
                let sell_percentage = token_change.abs() / entry.amount_held;
                entry.cost_basis *= 1.0 - sell_percentage;

                logger.log(format!(
                    "Adjusted cost basis for sell: new={} (reduced by {}%)", 
                    entry.cost_basis, sell_percentage * 100.0
                ));
            }
        }

        // Always update amount held with actual balance
        entry.amount_held = actual_token_balance;

        // Always update current price
        entry.current_price = price;

        // Update highest price if applicable
        if price > entry.highest_price {
            entry.highest_price = price;
        }

        // Update lowest price if applicable (initialize or update if lower)
        if entry.lowest_price == 0.0 || price < entry.lowest_price {
            entry.lowest_price = price;
        }

        // Update price history
        entry.price_history.push_back(price);
        if entry.price_history.len() > 20 {  // Keep last 20 prices
            entry.price_history.pop_front();
        }

        // Log current metrics
        let pnl = if entry.entry_price > 0.0 {
            ((price - entry.entry_price) / entry.entry_price) * 100.0
        } else {
            0.0
        };

        logger.log(format!(
            "Token metrics for {}: Price: {}, Entry: {}, Highest: {}, Lowest: {}, PNL: {:.2}%, Balance: {}",
            token_mint, price, entry.entry_price, entry.highest_price, entry.lowest_price, pnl, actual_token_balance
        ));

        Ok(())
    }
Enter fullscreen mode Exit fullscreen mode

https://github.com/deniyuda348/pump-fun-pump-swap-sniper-copy-bot/wiki/diagram-about-selling

Image description

Top comments (0)