Rust BTC support/resistance levels Analysis
2025-06-03
use reqwest;
use serde::Deserialize;
use std::collections::HashMap;
use tokio;
#[derive(Debug, Clone)]
struct OHLCV {
high: f64,
low: f64,
close: f64,
}
#[derive(Debug)]
struct SupportResistanceLevel {
price: f64,
strength: i32,
level_type: String, // "support" or "resistance"
}
struct BinanceClient {
client: reqwest::Client,
base_url: String,
}
impl BinanceClient {
fn new() -> Self {
Self {
client: reqwest::Client::new(),
base_url: "https://api.binance.com".to_string(),
}
}
async fn get_klines(&self, symbol: &str, interval: &str, limit: u16) -> Result<Vec<OHLCV>, Box<dyn std::error::Error>> {
let url = format!(
"{}/api/v3/klines?symbol={}&interval={}&limit={}",
self.base_url, symbol, interval, limit
);
let response = self.client.get(&url).send().await?;
let klines: Vec<Vec<serde_json::Value>> = response.json().await?;
let mut ohlcv_data = Vec::new();
for kline in klines {
let ohlcv = OHLCV {
high: kline[2].as_str().unwrap().parse()?,
low: kline[3].as_str().unwrap().parse()?,
close: kline[4].as_str().unwrap().parse()?,
};
ohlcv_data.push(ohlcv);
}
Ok(ohlcv_data)
}
async fn get_current_price(&self, symbol: &str) -> Result<f64, Box<dyn std::error::Error>> {
let url = format!("{}/api/v3/ticker/price?symbol={}", self.base_url, symbol);
let response = self.client.get(&url).send().await?;
#[derive(Deserialize)]
struct PriceResponse {
price: String,
}
let price_data: PriceResponse = response.json().await?;
Ok(price_data.price.parse()?)
}
}
struct TechnicalAnalyzer;
impl TechnicalAnalyzer {
// Find pivot highs and lows
fn find_pivots(data: &[OHLCV], window: usize) -> (Vec<(usize, f64)>, Vec<(usize, f64)>) {
let mut pivot_highs = Vec::new();
let mut pivot_lows = Vec::new();
for i in window..data.len() - window {
let current_high = data[i].high;
let current_low = data[i].low;
// Check if current high is higher than surrounding highs
let is_pivot_high = (i - window..i)
.chain(i + 1..=i + window)
.all(|j| data[j].high < current_high);
// Check if current low is lower than surrounding lows
let is_pivot_low = (i - window..i)
.chain(i + 1..=i + window)
.all(|j| data[j].low > current_low);
if is_pivot_high {
pivot_highs.push((i, current_high));
}
if is_pivot_low {
pivot_lows.push((i, current_low));
}
}
(pivot_highs, pivot_lows)
}
// Calculate support and resistance levels
fn calculate_support_resistance(
_data: &[OHLCV],
pivot_highs: &[(usize, f64)],
pivot_lows: &[(usize, f64)],
tolerance: f64,
) -> Vec<SupportResistanceLevel> {
let mut levels = Vec::new();
let mut price_clusters: HashMap<i32, Vec<(f64, String)>> = HashMap::new();
// Group pivot highs into clusters (potential resistance)
for &(_idx, price) in pivot_highs {
let price_key = (price / tolerance) as i32;
price_clusters
.entry(price_key)
.or_insert_with(Vec::new)
.push((price, "resistance".to_string()));
}
// Group pivot lows into clusters (potential support)
for &(_idx, price) in pivot_lows {
let price_key = (price / tolerance) as i32;
price_clusters
.entry(price_key)
.or_insert_with(Vec::new)
.push((price, "support".to_string()));
}
// Convert clusters to support/resistance levels
for (_, cluster) in price_clusters {
if cluster.len() >= 2 {
// Only consider levels with multiple touches
let avg_price = cluster.iter().map(|(p, _)| p).sum::<f64>() / cluster.len() as f64;
let level_type = cluster[0].1.clone();
levels.push(SupportResistanceLevel {
price: avg_price,
strength: cluster.len() as i32,
level_type,
});
}
}
// Sort by strength (number of touches)
levels.sort_by(|a, b| b.strength.cmp(&a.strength));
levels
}
// Calculate RSI for additional confirmation
fn calculate_rsi(data: &[OHLCV], period: usize) -> Vec<f64> {
if data.len() < period + 1 {
return Vec::new();
}
let mut gains = Vec::new();
let mut losses = Vec::new();
// Calculate price changes
for i in 1..data.len() {
let change = data[i].close - data[i - 1].close;
if change > 0.0 {
gains.push(change);
losses.push(0.0);
} else {
gains.push(0.0);
losses.push(-change);
}
}
let mut rsi_values = Vec::new();
// Calculate initial average gain and loss
let mut avg_gain: f64 = gains[..period].iter().sum::<f64>() / period as f64;
let mut avg_loss: f64 = losses[..period].iter().sum::<f64>() / period as f64;
// Calculate RSI
for i in period..gains.len() {
if avg_loss == 0.0 {
rsi_values.push(100.0);
} else {
let rs = avg_gain / avg_loss;
let rsi = 100.0 - (100.0 / (1.0 + rs));
rsi_values.push(rsi);
}
// Update averages using smoothing
avg_gain = (avg_gain * (period - 1) as f64 + gains[i]) / period as f64;
avg_loss = (avg_loss * (period - 1) as f64 + losses[i]) / period as f64;
}
rsi_values
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = BinanceClient::new();
println!("🔍 Fetching BTCUSDT data from Binance...");
// Get current price
let current_price = client.get_current_price("BTCUSDT").await?;
println!("📊 Current BTCUSDT Price: ${:.2}", current_price);
// Get historical data (500 4-hour candles for better analysis)
let klines = client.get_klines("BTCUSDT", "4h", 500).await?;
println!("📈 Retrieved {} candles for analysis", klines.len());
// Find pivot points
let (pivot_highs, pivot_lows) = TechnicalAnalyzer::find_pivots(&klines, 5);
println!("🔍 Found {} pivot highs and {} pivot lows", pivot_highs.len(), pivot_lows.len());
// Calculate support and resistance levels
let tolerance = current_price * 0.01; // 1% tolerance for clustering
let levels = TechnicalAnalyzer::calculate_support_resistance(
&klines,
&pivot_highs,
&pivot_lows,
tolerance,
);
// Calculate RSI for current market condition
let rsi_values = TechnicalAnalyzer::calculate_rsi(&klines, 14);
let current_rsi = rsi_values.last().unwrap_or(&50.0);
println!("\n📊 BTCUSDT Technical Analysis Report");
println!("=====================================");
println!("Current Price: ${:.2}", current_price);
println!("Current RSI(14): {:.2}", current_rsi);
// Market condition based on RSI
let market_condition = match current_rsi {
rsi if *rsi > 70.0 => "Overbought 🔴",
rsi if *rsi < 30.0 => "Oversold 🟢",
_ => "Neutral 🟡",
};
println!("Market Condition: {}", market_condition);
println!("\n🎯 Key Support & Resistance Levels:");
println!("===================================");
// Separate and display support and resistance levels
let mut support_levels: Vec<_> = levels.iter()
.filter(|l| l.level_type == "support" && l.price < current_price)
.collect();
support_levels.sort_by(|a, b| b.price.partial_cmp(&a.price).unwrap());
let mut resistance_levels: Vec<_> = levels.iter()
.filter(|l| l.level_type == "resistance" && l.price > current_price)
.collect();
resistance_levels.sort_by(|a, b| a.price.partial_cmp(&b.price).unwrap());
println!("\n🛡️ SUPPORT LEVELS (below current price):");
for (i, level) in support_levels.iter().take(5).enumerate() {
let distance = ((current_price - level.price) / current_price) * 100.0;
println!(" {}. ${:.2} | Strength: {} touches | Distance: -{:.2}%",
i + 1, level.price, level.strength, distance);
}
println!("\n🚫 RESISTANCE LEVELS (above current price):");
for (i, level) in resistance_levels.iter().take(5).enumerate() {
let distance = ((level.price - current_price) / current_price) * 100.0;
println!(" {}. ${:.2} | Strength: {} touches | Distance: +{:.2}%",
i + 1, level.price, level.strength, distance);
}
// Trading recommendations
println!("\n💡 Trading Insights:");
println!("===================");
if let Some(nearest_support) = support_levels.first() {
let support_distance = ((current_price - nearest_support.price) / current_price) * 100.0;
println!("• Nearest Support: ${:.2} ({:.2}% below)", nearest_support.price, support_distance);
if support_distance < 2.0 {
println!(" ⚠️ Price is very close to support - watch for bounce or breakdown");
}
}
if let Some(nearest_resistance) = resistance_levels.first() {
let resistance_distance = ((nearest_resistance.price - current_price) / current_price) * 100.0;
println!("• Nearest Resistance: ${:.2} ({:.2}% above)", nearest_resistance.price, resistance_distance);
if resistance_distance < 2.0 {
println!(" ⚠️ Price is very close to resistance - watch for rejection or breakout");
}
}
// Volume analysis suggestion
println!("\n📊 Next Steps for Enhanced Analysis:");
println!("• Monitor volume at key levels for confirmation");
println!("• Watch for price action patterns near support/resistance");
println!("• Consider multiple timeframes for confluence");
Ok(())
}
// Add to Cargo.toml:
/*
[dependencies]
reqwest = { version = "0.11", features = ["json"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1.0", features = ["full"] }
*/
This Rust code is a comprehensive technical analysis tool for cryptocurrency trading, specifically designed to analyze BTC/USDT (Bitcoin/Tether) price data from the Binance exchange. Let me break down its components and functionality:
Key Components:
- BinanceClient:
- Handles API communication with Binance
- Methods to fetch:
- K-line/candlestick data (
get_klines) - Current price (
get_current_price)
- K-line/candlestick data (
- OHLCV Struct:
- Stores price data (High, Low, Close - Open and Volume are not used in this implementation)
- TechnicalAnalyzer:
- Core analysis functionality:
- Finds pivot highs/lows (
find_pivots) - Calculates support/resistance levels (
calculate_support_resistance) - Computes RSI (Relative Strength Index) (
calculate_rsi)
- Finds pivot highs/lows (
- Core analysis functionality:
- SupportResistanceLevel:
- Stores identified levels with:
- Price value
- Strength (number of touches)
- Type (support/resistance)
- Stores identified levels with:
Workflow:
- Data Fetching:
- Gets 500 candles of 4-hour BTC/USDT data
- Retrieves current price
- Technical Analysis:
- Identifies pivot points (local highs/lows)
- Clusters similar price levels to find support/resistance
- Calculates RSI for overbought/oversold conditions
- Reporting:
- Displays current price and RSI
- Lists key support/resistance levels with:
- Distance from current price
- Strength (number of touches)
- Provides trading insights based on proximity to levels
Key Technical Indicators:
- Pivot Points:
- Identifies significant highs/lows within a window (5 periods)
- Used as basis for support/resistance levels
- Support/Resistance:
- Levels are clustered with 1% tolerance
- Only levels with ≥ 2 touches are considered
- Sorted by strength (more touches = stronger level)
- RSI (14-period):
- Standard momentum oscillator
- Used to identify overbought (>70) and oversold (<30) conditions
Trading Insights:
The analysis provides:
- Visual distance to nearest support/resistance
- Warnings when price approaches key levels (<2% away)
- Market condition based on RSI
- Suggested next steps for deeper analysis
Strengths:
- Uses multiple confirmation methods (price levels + RSI)
- Provides quantitative strength metrics for levels
- Clear visualization of distance to key levels
- Practical trading suggestions
Potential Enhancements:
- Add volume analysis
- Incorporate more timeframes
- Add additional indicators (MACD, moving averages)
- Implement breakout detection
- Add backtesting capability
This is a solid foundation for a technical analysis tool that could be extended with more features for comprehensive trading analysis. The code is well-structured and follows Rust best practices with proper error handling and async/await patterns.