Automated Report Distribution¶
This guide explains how to set up and use the automated report distribution system in DSTA.
Overview¶
The report scheduler automatically generates and distributes trading reports via:
- Email (SMTP)
- Telegram Bot
- Local file storage
- Report archiving with retention policies
Supports daily, weekly, and monthly schedules with customizable templates.
Quick Start¶
1. Configuration¶
Set up environment variables for email and Telegram:
# Email configuration
export SMTP_HOST="smtp.gmail.com"
export SMTP_PORT="587"
export SMTP_USERNAME="your-email@gmail.com"
export SMTP_PASSWORD="your-app-password"
# Telegram configuration
export TELEGRAM_BOT_TOKEN="your-bot-token"
2. Basic Usage¶
from src.analytics.report_scheduler import (
ReportDistributor,
ReportScheduler,
ReportConfig,
)
from src.analytics.reports.daily import DailyReportGenerator
# Create distributor
distributor = ReportDistributor()
# Create scheduler
scheduler = ReportScheduler(distributor)
# Define report generator
def generate_daily_report():
generator = DailyReportGenerator()
# ... load your data
report = generator.generate_report(...)
return report
# Configure report
config = ReportConfig(
name='Daily Trading Summary',
report_type='daily',
generator=generate_daily_report,
schedule_type='daily',
schedule_time='18:00', # 6 PM every day
email_enabled=True,
email_recipients=['trader@example.com'],
formats=['html', 'text'],
)
# Add to scheduler
scheduler.add_report(config)
# Run scheduler (blocking)
scheduler.run()
Configuration Options¶
ReportConfig¶
Complete configuration options:
config = ReportConfig(
# Basic settings
name='My Report', # Report name
report_type='daily', # 'daily', 'monthly', 'custom'
generator=my_generator_func, # Callable that returns report
# Schedule
schedule_type='daily', # 'daily', 'weekly', 'monthly'
schedule_time='09:00', # Time in HH:MM format
# Email distribution
email_enabled=True,
email_recipients=[
'trader1@example.com',
'trader2@example.com',
],
# Telegram distribution
telegram_enabled=True,
telegram_chat_ids=[
'123456789', # Get from Telegram
'987654321',
],
# File storage
file_enabled=True,
file_path=Path('reports/daily'),
# Export formats
formats=['html', 'text', 'json'],
# Archiving
archive_enabled=True,
archive_path=Path('reports/archive/daily'),
archive_retention_days=90, # Keep for 90 days
# Error handling
retry_on_failure=True,
max_retries=3,
retry_delay_minutes=5,
)
Schedule Types¶
Daily Reports¶
config = ReportConfig(
name='Daily Summary',
schedule_type='daily',
schedule_time='18:00', # Every day at 6 PM
...
)
Weekly Reports¶
config = ReportConfig(
name='Weekly Analysis',
schedule_type='weekly',
schedule_time='monday 09:00', # Every Monday at 9 AM
...
)
Monthly Reports¶
config = ReportConfig(
name='Monthly Performance',
schedule_type='monthly',
schedule_time='09:00', # First of month at 9 AM
...
)
Distribution Channels¶
Email¶
Gmail Setup¶
- Enable 2-factor authentication
- Generate app-specific password
- Configure environment:
export SMTP_HOST="smtp.gmail.com"
export SMTP_PORT="587"
export SMTP_USERNAME="your-email@gmail.com"
export SMTP_PASSWORD="your-app-password"
Custom SMTP Server¶
distributor = ReportDistributor(
smtp_host='mail.yourcompany.com',
smtp_port=587,
smtp_username='reports@yourcompany.com',
smtp_password='password',
)
Email Content¶
Emails include: - HTML formatted report (primary) - Plain text version (fallback) - Attachments (optional)
Telegram¶
Bot Setup¶
- Create bot with @BotFather
- Get bot token
- Get your chat ID:
- Message @userinfobot
- Or check https://api.telegram.org/bot{TOKEN}/getUpdates
Configuration¶
Telegram Message Format¶
Telegram messages include: - Report title and timestamp - Summary (first few lines) - Full report as attachment (optional) - HTML formatting supported
File Storage¶
Reports are saved locally:
config = ReportConfig(
file_enabled=True,
file_path=Path('reports/daily'),
formats=['html', 'text', 'json'],
)
Files are named: {report_name}_{timestamp}.{format}
Example: Daily_Trading_Summary_20260126_180000.html
Report Generators¶
Daily Report¶
from src.analytics.reports.daily import DailyReportGenerator
def generate_daily():
generator = DailyReportGenerator()
# Load data for today
portfolio = load_portfolio_data()
trades = load_trades_data()
positions = load_positions()
return generator.generate_report(
date=datetime.now().date(),
portfolio=portfolio,
trades=trades,
positions=positions,
)
Monthly Report¶
from src.analytics.reports.monthly import MonthlyReportGenerator
def generate_monthly():
generator = MonthlyReportGenerator()
# Load data for current month
year = datetime.now().year
month = datetime.now().month
portfolio_values = load_monthly_portfolio()
trades = load_monthly_trades()
return generator.generate_report(
year=year,
month=month,
portfolio_values=portfolio_values,
trades=trades,
)
Custom Report¶
def generate_custom():
"""Your custom report generator."""
# Generate report data
data = analyze_trading_performance()
# Create report object with export methods
class CustomReport:
def export_html(self, report):
return "<html>...</html>"
def export_text(self, report):
return "Text report..."
return CustomReport()
Running the Scheduler¶
As a Background Service¶
# scheduler.py
import logging
from src.analytics.report_scheduler import ReportScheduler, ReportDistributor
logging.basicConfig(level=logging.INFO)
distributor = ReportDistributor()
scheduler = ReportScheduler(distributor)
# Add all your reports
scheduler.add_report(daily_config)
scheduler.add_report(weekly_config)
scheduler.add_report(monthly_config)
# Run forever
scheduler.run() # Blocking
Run as daemon:
With systemd¶
Create /etc/systemd/system/dsta-reports.service:
[Unit]
Description=DSTA Report Scheduler
After=network.target
[Service]
Type=simple
User=dsta
WorkingDirectory=/path/to/dsta
ExecStart=/path/to/python scheduler.py
Restart=always
[Install]
WantedBy=multi-user.target
Enable and start:
sudo systemctl enable dsta-reports
sudo systemctl start dsta-reports
sudo systemctl status dsta-reports
Manual Execution¶
Run report once (for testing):
# Run specific report
scheduler.run_once('Daily Trading Summary')
# Run all reports
scheduler.run_once()
Archive Management¶
Reports are automatically archived with configurable retention:
config = ReportConfig(
archive_enabled=True,
archive_path=Path('reports/archive/daily'),
archive_retention_days=90, # Keep for 90 days
...
)
Archive structure:
reports/
└── archive/
├── daily/
│ ├── 20260126_180000.html
│ ├── 20260126_180000.text
│ └── ...
└── monthly/
├── 20260101_090000.html
└── ...
Old reports are automatically deleted after retention period.
Error Handling¶
Retry Configuration¶
If report generation or distribution fails: 1. Logs error 2. Waits retry_delay_minutes 3. Retries up to max_retries times 4. Logs final failure if all attempts fail
Monitoring¶
Check logs for issues:
import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('reports.log'),
logging.StreamHandler(),
]
)
Complete Example¶
#!/usr/bin/env python3
"""
DSTA Report Scheduler
Automated daily and monthly reports via email and Telegram.
"""
import logging
from pathlib import Path
from datetime import datetime
from src.analytics.report_scheduler import (
ReportDistributor,
ReportScheduler,
ReportConfig,
)
from src.analytics.reports.daily import DailyReportGenerator
from src.analytics.reports.monthly import MonthlyReportGenerator
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('logs/reports.log'),
logging.StreamHandler(),
]
)
# Create distributor
distributor = ReportDistributor()
# Create scheduler
scheduler = ReportScheduler(distributor)
# Daily report generator
def generate_daily():
generator = DailyReportGenerator()
# TODO: Load your actual data
return generator.generate_report(...)
# Monthly report generator
def generate_monthly():
generator = MonthlyReportGenerator()
# TODO: Load your actual data
return generator.generate_report(...)
# Configure daily report
daily_config = ReportConfig(
name='Daily Trading Summary',
report_type='daily',
generator=generate_daily,
schedule_type='daily',
schedule_time='18:00',
email_enabled=True,
email_recipients=['trader@example.com'],
telegram_enabled=True,
telegram_chat_ids=['123456789'],
formats=['html', 'text'],
archive_retention_days=30,
)
# Configure monthly report
monthly_config = ReportConfig(
name='Monthly Performance Report',
report_type='monthly',
generator=generate_monthly,
schedule_type='monthly',
schedule_time='09:00',
email_enabled=True,
email_recipients=['trader@example.com', 'manager@example.com'],
formats=['html', 'json'],
archive_retention_days=365,
)
# Add reports to scheduler
scheduler.add_report(daily_config)
scheduler.add_report(monthly_config)
# Run scheduler
if __name__ == '__main__':
logging.info("Starting DSTA Report Scheduler...")
scheduler.run()
Troubleshooting¶
Email not sending¶
- Check SMTP credentials
- Verify 2FA and app password (Gmail)
- Check firewall/port 587
- Review logs for error details
Telegram not sending¶
- Verify bot token
- Check chat ID
- Ensure bot is in group (for group chats)
- Test with curl:
Reports not generated¶
- Check report generator function
- Verify data sources are accessible
- Review logs for exceptions
- Test generator manually:
Schedule not running¶
- Verify
schedule_timeformat - Check scheduler is running
- Test with
run_once()first - Review system time zone
Best Practices¶
- Test generators before scheduling
- Start with file distribution then add email/Telegram
- Monitor logs regularly
- Set appropriate retention for archives
- Use retry logic for critical reports
- Keep credentials secure (use environment variables)
- Test email templates across devices
- Document custom generators for maintenance
Security¶
- Never commit credentials to git
- Use environment variables or secret managers
- Restrict file permissions on config files
- Use app-specific passwords (Gmail)
- Rotate Telegram bot tokens periodically
- Monitor for failed delivery attempts
Support¶
For issues with report scheduling:
- Check logs in
logs/reports.log - Verify configuration
- Test individual components
- Open GitHub issue with details