Overview
The Bot Interface provides the foundation for all PROPPR Telegram bots, including command handlers, settings management, and user interaction patterns.
Base Bot Structure
Command Handlers
All PROPPR bots implement standard command handlers:
def start_command(update: Update, context: CallbackContext):
"""Handle /start command - NO RESTRICTIONS"""
user_id = update.effective_user.id
username = update.effective_user.username or "User"
# Ensure user has default settings
settings = db_manager.get_user_settings(user_id)
# Track command usage
db_manager.track_command_usage(user_id, "start")
Available Commands:
/start - Initialize bot and show welcome message
/settings - Manage user preferences
/stats - View user statistics
/help - Display help information
/scan - Search for arbitrage opportunities (ArbBot)
/connect <code> - Link Telegram account to App
Settings Management
def settings_command(update: Update, context: CallbackContext):
"""Handle /settings command"""
user_id = update.effective_user.id
settings = db_manager.get_user_settings(user_id)
keyboard = [
[InlineKeyboardButton("π· Change Stake", callback_data="set_stake")],
[InlineKeyboardButton("π Min Margin", callback_data="set_margin")],
[InlineKeyboardButton("π Bookmakers", callback_data="manage_bookmakers")]
]
Settings Options:
- Default stake amount
- Minimum arbitrage margin
- Enabled bookmakers
- Sport filters
- Time filters
- Exchange commissions
- Alert preferences
Callback Handler Pattern
def button_callback(update: Update, context: CallbackContext):
"""Handle button callbacks"""
query = update.callback_query
query.answer()
user_id = update.effective_user.id
data = query.data
if data == "set_stake":
# Handle stake input
query.edit_message_text("π· Enter your default stake amount:")
return STAKE_INPUT
User Settings Schema
Default stake amount in currency
Minimum arbitrage margin percentage
Dictionary of enabled bookmakers{
"Bet365": {"enabled": True},
"Pinnacle": {"enabled": False}
}
Dictionary of enabled sports
Whether to receive alerts
Premium subscription status
exchange_commission_rates
Custom commission rates for exchanges{
"Betfair Exchange": 2.0,
"Matchbook": 1.5
}
Bookmaker Management
Get All Bookmakers
def get_all_available_bookmakers() -> dict:
"""Get all available bookmakers (defaults + discovered)"""
return {
"Bet365": {"enabled": True, "region": "global"},
"Pinnacle": {"enabled": True, "region": "global"},
"Betfair Exchange": {"enabled": True, "region": "uk"}
}
Toggle Bookmaker
def toggle_bookmaker(user_id: int, bookmaker: str, enabled: bool):
"""Toggle bookmaker on/off for user"""
db_manager.user_settings.update_one(
{"user_id": user_id},
{"$set": {f"bookmaker_settings.{bookmaker}.enabled": enabled}}
)
Bookmaker Flags
BOOKMAKER_FLAGS = {
"Bet365": "π",
"Pinnacle": "π",
"BetMGM": "πΊπΈ",
"SkyBet": "π¬π§",
"Betano": "π§π·"
}
def get_bookmaker_flag(bookmaker_name: str) -> str:
"""Get the flag emoji for a bookmaker"""
return BOOKMAKER_FLAGS.get(bookmaker_name, "")
Alert System
Send Alert
def send_alert_to_user(user_id: int, arb_data: dict):
"""Send arbitrage alert to a specific user"""
# Check if alert already sent
if db_manager.has_alert_been_sent(arb_data["id"], user_id):
return False
# Apply user filters
filtered = api_service.apply_user_filters([arb_data], settings)
if not filtered:
return False
# Format and send
alert_text, reply_markup = AlertFormatter.format_arbitrage_alert(
arb_data, user_stake, user_id
)
bot.send_message(
chat_id=user_id,
text=alert_text,
reply_markup=reply_markup,
parse_mode=ParseMode.MARKDOWN
)
db_manager.mark_alert_sent(arb_data["id"], user_id)
return True
Premium Status
Check Premium
def check_user_premium_status(user_id: int) -> tuple:
"""Check if user has premium subscription"""
try:
member = updater.bot.get_chat_member(SUBSCRIPTION_CHANNEL_ID, user_id)
is_premium = member.status in ['member', 'administrator', 'creator']
return is_premium, True
except Exception as e:
return False, False
Premium Features
- No margin cap (receive ALL arbitrages)
- No rate limiting
- Custom stake amounts
- All sports and markets
- Priority support
Rate Limiting
Demo User Limits
# Demo users (non-premium)
if not is_premium and arb_margin <= 1.0:
# 5-minute cooldown between alerts
if time_since_last < 300:
return False
# Max 6 alerts per hour
if alerts_last_hour >= 6:
return False
Error Handling
Safe Message Edit
def safe_edit_message(query, text, reply_markup=None):
"""Safely edit a message, catching identical content errors"""
try:
query.message.edit_text(
text=text,
reply_markup=reply_markup
)
except BadRequest as e:
if "Message is not modified" in str(e):
# Message is identical - ignore
pass
else:
raise
Handle Blocked Users
try:
bot.send_message(chat_id=user_id, text=message)
except TelegramError as e:
if "bot was blocked" in str(e).lower():
db_manager.disable_alerts_for_blocked_user(user_id)
active_users.remove(user_id)
References