Automated Exchange Rate Posting System

Automated Exchange Rate Posting SystemPython Project

Automated Exchange Rate Posting System

HeyMrDigital LogoAutomated Exchange Rate Engine

Our client required an end-to-end, live Exchange Rate Engine to solve two key business problems:

  • Automated Posting: Automate the daily posting of exchange rates (both text and a custom-branded image) to platforms like Telegram and Facebook, three times per day.
  • On-Demand Live Rate: Provide customers an on-demand live rate via a bot, with a price that the business would guarantee for 30 minutes (or a custom timeframe), creating a transparent and trustworthy system.

😟 The Client's Problem

The client's staff was spending several hours every day on repetitive, high-stakes manual work. This created three major bottlenecks:

  • Intense Manual Labor: Team members had to manually fetch rates from multiple sources, calculate business-specific pricing, design a new rate graphic, and post it to Telegram and Facebook three times a day (morning, lunch, and evening).
  • Constant Customer Inquiries: Their inbox was flooded with "What's the rate?" messages. The manually posted rates would quickly become outdated, forcing customers to ask for updates.
  • Lost Business & Trust: This delay and lack of a "live" rate created customer frustration and lost opportunities. They needed a transparent system that customers could trust for real-time transactions.

💡 The Solution

We designed and built a comprehensive, two-part automated system that functions as both a scheduled broadcaster and an on-demand transactional tool.

Part 1: The Scheduled Autoposter

  • Runs Automatically: Triggers three times per day: morning, lunch, and evening via server-side cron jobs.
  • Fetches Live Data: Pulls rate information from multiple, separate live data sources.
  • Applies Business Logic: Uses the calculate.py script to consolidate data, apply custom margins, and determine the final business rate.
  • Generates Branded Media: Feeds the rate into photogenerate.py (PIL) to dynamically create a custom-branded image for the post.
  • Posts to Socials: Automatically posts the formatted text and the new image to Telegram and Facebook using their APIs.

Part 2: The On-Demand Live Rate Bot

  • 24/7 Availability: Customers can message the bot on Telegram or Facebook Messenger at any time.
  • Real-Time Calculation: The bot instantly triggers the full calculation engine using the most up-to-the-second data.
  • The "30-Minute Rate Lock": The bot provides a guaranteed exchange rate that is locked in for 30 minutes, giving customers a secure window to transact.
  • Scalable: Architecture designed to add more platforms (WhatsApp, LINE, Instagram) in the future.

🛠️ The Technology

This engine is a robust, server-side Python application chosen for reliability and scalability. Key technologies:

  • Core Logic: Python
  • APIs & Integration: Telegram Bot API, Facebook Graph API
  • Image Generation: PIL (Pillow)
  • Automation & Scheduling: cron jobs
  • Server & Deployment: Managed Linux servers with resilient uptime and error logging

⚙️ The Process

We followed an agile process: discovery & strategy, architecture design (separating scheduled poster from on-demand bot), core development (calculate.py, photogenerate.py, autopost scripts), deployment & testing, and handover & training.

🏆 The Result (The "Win")

  • Saved 10+ hours per week by eliminating manual posting and calculations.
  • Increased customer trust through the 30-minute guaranteed rate.
  • Enabled 24/7 lead conversion via the on-demand bot.
  • Eliminated human error; improved consistency and reliability.

Code Showcase

calculate.py
def get_median_price(file_path):
    with open(file_path, 'r') as f:
        for line in f:
            if 'Median price' in line:
                median_price_str = line.split(': ')[1].strip()
                median_price_str = median_price_str.replace(',', '')
                median_price = float(median_price_str)
                return median_price

# get median price for TYUE @ ttK
tyue_ttk = get_median_price('buy_answers.txt')
print("TYUE @ ttK Median Price:", tyue_ttk)

# get median price for TYUE @ CRD
tyue_crd = get_median_price('sell_answers.txt')
print("TYUE @ CRD Median Price:", tyue_crd)

def get_rate(profit_pct):
    crd_to_tyue = 1 / tyue_crd  # calculate the value of 1 crd in tyue
    tyue_to_ttk = tyue_ttk  # the value of 1 TYUE in TTK
    crd_to_ttk = crd_to_tyue * tyue_to_ttk  # calculate the value of 1 crd in ttK
    crd_to_ttk_rounded = round(crd_to_ttk, 4)  # round the result to 4 decimal places
    new_round = round(crd_to_ttk_rounded, 2)
    # calculate the profit and add it to the new_round value
    profit_amount = new_round * profit_pct / 100
    new_round_with_profit = new_round + profit_amount
    final_round = round(new_round_with_profit,2)
    return final_round
#profit_pct = float(input("Enter the profit percentage: "))
profit_pct = 1
get_rate(profit_pct)
...
***tgenerator.py
import calculate
from datetime import datetime
from pytz import timezone

with open('custom_text.txt', 'r', encoding='utf-8') as f:
    c_text = f.read()
with open('custom_text1.txt', 'r', encoding='utf-8') as f:
    c_text1 = f.read()
)
...
***togenerate.py
from datetime import datetime
from pytz import timezone
from PIL import Image, ImageDraw, ImageFont
import configparser
import os
import logging
import calculate

logging.basicConfig(filename='photogenerate.log', level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')

def generate_new_image():
    try:
        # Get the path of the current directory
        current_directory = os.path.dirname(os.path.abspath(__file__))
        # Open the original image
        original_image_path = os.path.join(current_directory, "original_image.jpg")
        if not os.path.exists(original_image_path):
            logging.error(f"Original image not found at {original_image_path}")
            return None
        with Image.open(original_image_path) as img:
            # Create an ImageDraw object
            draw = ImageDraw.Draw(img)
            ...
    except Exception as e:
        logging.error(f"Error generating new image: {e}")
        return None

if __name__ == "__main__":
    new_image_path = generate_new_image()
...