# Project export: WattWise

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: Cal Hacks 11.0
- Tagline: Decentralized energy trading platform. Utilizes existing power grid infrastructure to facilitate peer-to-peer energy trading.
- Devpost: https://devpost.com/software/decentralized-energy-exchange
- GitHub: https://github.com/hem8705/calhacks_
- Team: 2 GitHub contributor(s) — hem (12 commits), rit-123 (3 commits)

## Devpost submission (written by the team)

### Inspiration

and

### What it does

Paying Utilities is always a mess. The prices are never consistent, and the consumer never really gets a transparent way to decide their own prices, nor have open access to information about it. Producers, especially those who own renewable sources of energy sources of energy such as solar panels, on the other hand tend to have a surplus of energy, which is often times wasted. The one thing in common consumers and producers have is the power grid they're connected to - and we make it possible to have an open market, where the sellers and buyers themselves decide their prices for their own levels of consumption/production.

### How we built it

Fetch.ai Agents for each consumer and producer, and the market they are based on. We used ML models with Tensorflow to analyze the market prices to provide the stakeholders with open access to this information that is based on statistical data, and parameters such as Location, Weather, Season, Time, etc. We used Flask and React as the basic tech stack for the user interfaces and application.

### Challenges we ran into

We initially started with an idea to create a decentralized blockchain network, which turned out to be out of scope for the time period of the hackathon, with the additional complexity of each Fetch.ai Agent. We were also focused too much on the technical backing of the project that we almost ignored the UI experience, which made it difficult to create a great working demo.

### Accomplishments we're proud of

This was a very technically complex idea that we decided to take on. Even though we had to downgrade the technical complexity we initially hoped to build, it's a great proof of concept as an interface that can be built upon heavily in the future.

### What we learned

We learnt the real technical nuances that go behind building decentralized systems from scratch.

### What's next

We will go onto build the initial idea of the app we had. We will also make use of fetch.ai's AI agents to facilitate the free market exchange of energy, and to potentially make them Autonomous Economic Agents (AEAs). We will further strengthen the models the bidding and exchanges are based upon.

## README (from the GitHub repository)

Early hacky version of WattWise, Calhacks 11 submission. 

9/3/25: made edits for public view


## Detected evidence (automated analysis)

Indexed codebase: 25 recognized source files, 60 KB.
- CSS (language) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Flask (technology) — claimed on Devpost, not found in the code
- TensorFlow (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (66 of 66)

```
.gitignore
.vscode/launch.json
App.js
app.py
energy_trading_sim.py
energy_trading.py
frontend/.gitignore
frontend/package.json
frontend/public/index.html
frontend/public/manifest.json
frontend/public/robots.txt
frontend/README.md
frontend/src/App.css
frontend/src/App.js
frontend/src/App.test.js
frontend/src/EnergyTradingDashboard.js
frontend/src/index.css
frontend/src/index.js
frontend/src/reportWebVitals.js
frontend/src/setupTests.js
PredictionModel/NorPEN/Activities/Activities_1.csv
PredictionModel/NorPEN/Activities/Activities_3.csv
PredictionModel/NorPEN/Activities/Activities_5.csv
PredictionModel/NorPEN/Activities/Activities_6.csv
PredictionModel/NorPEN/Activities/Activities_7.csv
PredictionModel/NorPEN/Activities/Activities_9.csv
PredictionModel/NorPEN/Aggregate/Aggregate_1.csv
PredictionModel/NorPEN/Aggregate/Aggregate_3.csv
PredictionModel/NorPEN/Aggregate/Aggregate_5.csv
PredictionModel/NorPEN/Aggregate/Aggregate_6.csv
PredictionModel/NorPEN/Aggregate/Aggregate_7.csv
PredictionModel/NorPEN/Aggregate/Aggregate_9.csv
PredictionModel/NorPEN/ElectricityPrice.csv
PredictionModel/NorPEN/energy_data.csv
PredictionModel/NorPEN/predictor.py
PredictionModel/NorPEN/price_predictor.py
PredictionModel/NorPEN/PV/PV_1.csv
PredictionModel/NorPEN/PV/PV_3.csv
PredictionModel/NorPEN/PV/PV_5.csv
PredictionModel/NorPEN/PV/PV_6.csv
PredictionModel/NorPEN/PV/PV_7.csv
PredictionModel/NorPEN/PV/PV_9.csv
PredictionModel/NorPEN/ReadMe.txt
PredictionModel/NorPEN/SolarData.csv
PredictionModel/NorPEN/TimeOfUseSurvey.csv
PredictionModel/NorPEN/UtilityBilling/UtilityBilling_1.csv
PredictionModel/NorPEN/UtilityBilling/UtilityBilling_3.csv
PredictionModel/NorPEN/UtilityBilling/UtilityBilling_5.csv
PredictionModel/NorPEN/UtilityBilling/UtilityBilling_6.csv
PredictionModel/NorPEN/UtilityBilling/UtilityBilling_7.csv
PredictionModel/NorPEN/UtilityBilling/UtilityBilling_9.csv
PredictionModel/NorPEN/visualize.py
PredictionModel/NorPEN/WeatherData.csv
private_keys.json
README.md
requirements.txt
scrapped/agents/agent.py
scrapped/agents/pos_system.py
scrapped/agents/producer_agent/behaviours/behaviours.py
scrapped/agents/producer_agent/handlers/handlers.py
scrapped/agents/producer_agent/models/models.py
scrapped/agents/producer_agent/run.py
scrapped/energy_trading_sim.py
scrapped/requirements.txt
trained_lstm_model.joblib
trained_scaler.joblib
```

### Dependencies

- frontend/package.json: @testing-library/jest-dom@^5.17.0, @testing-library/react@^13.4.0, @testing-library/user-event@^13.5.0, react@^18.3.1, react-dom@^18.3.1, react-scripts@5.0.1, web-vitals@^2.1.4
- requirements.txt: uagents
- scrapped/requirements.txt: uagents

### Recent commits (newest first)

- changes
- all changes
- minor adjustments
- minor change in price_predictor
- changed with price_predictor.py
- made frontend and backend better
- the model
- Merge branch 'main' of https://github.com/hem8705/calhacks_
- modle
- added backend/frontend
- major changes
- removed the energy platform
- updates
- added uagents base
- added structure
- Initial commit

## Key source files (fetched from GitHub, selected and truncated for size)

### requirements.txt

```
uagents

```

### scrapped/requirements.txt

```
uagents

```

### frontend/package.json

```
{
  "name": "frontend",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

```

### App.js

```javascript
import EnergyTradingDashboard from './frontend/src/EnergyTradingDashboard';

function App() {
  return (
    <div className="App">
      <EnergyTradingDashboard />
    </div>
  );
}
```

### app.py

```python
from flask import Flask, jsonify, request
from flask_cors import CORS
import re
from collections import deque
import subprocess
import threading
import time

app = Flask(__name__)
CORS(app)

logs = deque(maxlen=10)
transactions = deque(maxlen=10)
chart_data = deque(maxlen=10)
total_energy = 0
average_price = 0
offers = []
producer_energy = 0

def parse_log_line(line):
    global total_energy, average_price, producer_energy
    if "Generated" in line:
        match = re.search(r"Generated (\d+\.\d+) units of energy", line)
        if match:
            amount = float(match.group(1))
            total_energy += amount
            producer_energy += amount
    elif "Sent offer" in line:
        match = re.search(r"(\d+\.\d+) units at (\d+\.\d+) per unit", line)
        if match:
            amount, price = map(float, match.groups())
            offers.append({"amount": amount, "price": price})
            chart_data.append({
                "timestamp": time.strftime("%H:%M:%S"),
                "amount": amount,
                "price": price
            })
            average_price = sum(offer["price"] for offer in offers) / len(offers)
    elif "Sent request" in line:
        match = re.search(r"(\d+\.\d+) units at max (\d+\.\d+) per unit", line)
        if match:
            amount, price = map(float, match.groups())
            chart_data.append({
                "timestamp": time.strftime("%H:%M:%S"),
                "amount": amount,
                "price": price
            })
    elif "Matched" in line:
        transactions.append(line.strip())
        match = re.search(r"Matched: (\d+\.\d+) units from (\w+) to (\w+) at (\d+\.\d+)", line)
        if match:
            amount, _, _, price = match.groups()
            amount, price = float(amount), float(price)
            producer_energy -= amount
    elif "Sold" in line or "Bought" in line:
        match = re.search(r"(\d+\.\d+) units at (\d+\.\d+) per unit", line)
        if match:
            amount, price = map(float, match.groups())
            if "Sold" in line:
                producer_energy -= amount
    logs.append(line.strip())

def run_energy_trading():
    process = subprocess.Popen(["python", "energy_trading.py"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
    for line in process.stdout:
        parse_log_line(line)

@app.route('/api/energy-data')
def get_energy_data():
    return jsonify({
        "logs": list(logs),
        "transactions": list(transactions),
        "chartData": list(chart_data),
        "totalEnergy": total_energy,
        "averagePrice": average_price,
        "offers": offers,
        "producerEnergy": producer_energy
    })

@app.route('/api/make-offer', methods=['POST'])
def make_offer():
    data = request.json
    amount = data.get('amount')
    price = data.get('price')
    
    if not amount or not price:
        return jsonify({"error": "Amount and price are required"}), 400

    global producer_energy
    if producer_energy < amount:
        return jsonify({"error": "Not enough energy available"}), 400

    offers.append({"amount": amount, "price": price})
    producer_energy -= amount
    parse_log_line(f"Sent offer: {amount:.2f} units at {price:.2f} per unit")
    
    return jsonify({"message": "Offer made successfully"}), 200

@app.route('/api/set-price-range', methods=['POST'])
def set_price_range():
    data = request.json
    min_price = data.get('minPrice')
    max_price = data.get('maxPrice')
    
    if min_price is None or max_price is None:
        return jsonify({"error": "Min price and max price are required"}), 400

    parse_log_line(f"Consumer set price range: min {min_price:.2f}, max {max_price:.2f}")
    
    return jsonify({"message": "Price range set successfully"}), 200

if __name__ == '__main__':
    # Start the energy trading simulation in a separate thread
    threading.Thread(target=run_energy_trading, daemon=True).start()
    app.run(debug=True)
    
```

### frontend/src/App.js

```javascript
import React from 'react';
import EnergyTradingDashboard from './EnergyTradingDashboard';

function App() {
  return (
    <div className="App">
      <EnergyTradingDashboard />
    </div>
  );
}

export default App;
```

### frontend/src/index.js

```javascript
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

reportWebVitals();
```

### energy_trading_sim.py

```python
import random
import time
from dataclasses import dataclass

@dataclass
class EnergyOffer:
    producer: str
    amount: float
    price: float

@dataclass
class EnergyRequest:
    consumer: str
    amount: float
    max_price: float

class Producer:
    def __init__(self, name, capacity):
        self.name = name
        self.capacity = capacity
        self.energy = 0
        self.balance = 0

    def generate_energy(self):
        self.energy = random.uniform(0, self.capacity)
        return self.energy

    def create_offer(self):
        amount = min(self.energy, random.uniform(0, self.energy))
        price = random.uniform(5, 15)
        return EnergyOffer(self.name, amount, price)

class Consumer:
    def __init__(self, name, max_consumption):
        self.name = name
        self.max_consumption = max_consumption
        self.energy_needed = 0
        self.balance = 1000  # Starting balance

    def calculate_energy_need(self):
        self.energy_needed = random.uniform(0, self.max_consumption)
        return self.energy_needed

    def create_request(self):
        amount = min(self.energy_needed, random.uniform(0, self.energy_needed))
        max_price = random.uniform(10, 20)
        return EnergyRequest(self.name, amount, max_price)

class EnergyMarket:
    def __init__(self):
        self.offers = []
        self.requests = []
        self.transactions = []

    def add_offer(self, offer):
        self.offers.append(offer)

    def add_request(self, request):
        self.requests.append(request)

    def match_offers_and_requests(self):
        for request in self.requests:
            for offer in self.offers:
                if offer.amount > 0 and request.amount > 0 and offer.price <= request.max_price:
                    trade_amount = min(offer.amount, request.amount)
                    self.transactions.append({
                        'seller': offer.producer,
                        'buyer': request.consumer,
                        'amount': trade_amount,
                        'price': offer.price
                    })
                    offer.amount -= trade_amount
                    request.amount -= trade_amount
        
        self.offers = [offer for offer in self.offers if offer.amount > 0]
        self.requests = [request for request in self.requests if request.amount > 0]

def simulate_energy_trading(producers, consumers, market, days):
    for day in range(days):
        print(f"Day {day + 1}")
        
        # Producers generate energy and create offers
        for producer in producers:
            energy_generated = producer.generate_energy()
            offer = producer.create_offer()
            market.add_offer(offer)
            print(f"{producer.name} generated {energy_generated:.2f} units and offered {offer.amount:.2f} units at {offer.price:.2f}")

        # Consumers calculate energy needs and create requests
        for consumer in consumers:
            energy_needed = consumer.calculate_energy_need()
            request = consumer.create_request()
            market.add_request(request)
            print(f"{consumer.name} needs {energy_needed:.2f} units and requested {request.amount:.2f} units at max {request.max_price:.2f}")

        # Match offers and requests
        market.match_offers_and_requests()

        # Process transactions
        for transaction in market.transactions:
            seller = next(p for p in producers if p.name == transaction['seller'])
            buyer = next(c for c in consumers if c.name == transaction['consumer'])
            amount = transaction['amount']
            price = transaction['price']
            total_cost = amount * price

            seller.balance += total_cost
            buyer.balance -= total_cost
            seller.energy -= amount
            buyer.energy_needed -= amount

            print(f"Transaction: {seller.name} sold {amount:.2f} units to {buyer.name} at {price:.2f} per unit")

        # Clear transactions for the next day
        market.transactions.clear()

        print("\n")
        time.sleep(1)  # Pause for 1 second between days

# Set up the simulation
producers = [Producer("SolarCo", 100), Producer("WindPower", 150)]
consumers = [Consumer("HomeTown", 80), Consumer("FactoryInc", 200)]
market = EnergyMarket()

# Run the simulation
simulate_energy_trading(producers, consumers, market, 5)



```

### energy_trading.py

```python
from uagents import Agent, Context, Model
from uagents.setup import fund_agent_if_low
import asyncio
import os
import multiprocessing
from PredictionModel.NorPEN.price_predictor import predict_price
import pandas as pd

# Retrieve the API key from environment variables
API_KEY = os.getenv("UAGENTS_API_KEY")

class EnergyOffer(Model):
    producer_id: str
    amount: float
    price: float

class EnergyRequest(Model):
    consumer_id: str
    amount: float
    max_price: float

class Transaction(Model):
    seller: str
    buyer: str
    amount: float
    price: float

class ProducerAgent(Agent):
    def __init__(self, name: str, capacity: float, port: int):
        super().__init__(name, port=port, endpoint=f"http://127.0.0.1:{port}")
        self.capacity = capacity
        self.energy = 0
        self.earnings = 0
        fund_agent_if_low(self.wallet.address())

class ConsumerAgent(Agent):
    def __init__(self, name: str, max_consumption: float, port: int):
        super().__init__(name, port=port, endpoint=f"http://127.0.0.1:{port}")
        self.max_consumption = max_consumption
        self.energy_needed = 0
        self.expenses = 0
        self.min_price = 0
        self.max_price = float('inf')
        fund_agent_if_low(self.wallet.address())

class MarketAgent(Agent):
    def __init__(self, port: int):
        super().__init__("market", port=port, endpoint=f"http://127.0.0.1:{port}")
        self.offers = []
        self.requests = []
        fund_agent_if_low(self.wallet.address())

def setup_producer_agent(agent: ProducerAgent):
    @agent.on_interval(period=60.0)
    async def generate_energy(ctx: Context):
        timestamp = pd.Timestamp.now()
        last_hour_consumption = agent.energy  # Use the current energy as last hour's consumption
        last_day_consumption = agent.capacity  # Use the capacity as a proxy for last day's consumption
        agent.energy = predict_price("energy_generation", timestamp, last_hour_consumption, last_day_consumption)
        ctx.logger.info(f"Generated {agent.energy:.2f} units of energy")

    @agent.on_interval(period=120.0)
    async def create_offer(ctx: Context):
        if agent.energy > 0:
            timestamp = pd.Timestamp.now()
            last_hour_consumption = agent.energy
            last_day_consumption = agent.capacity
            amount = min(agent.energy, predict_price("offer_amount", timestamp, last_hour_consumption, last_day_consumption))
            price = predict_price("energy_price", timestamp, last_hour_consumption, last_day_consumption)
            offer = EnergyOffer(producer_id=agent.name, amount=amount, price=price)
            await ctx.send("market", offer)
            ctx.logger.info(f"Sent offer: {amount:.2f} units at {price:.2f} per unit")

    @agent.on_message(model=Transaction)
    async def handle_transaction(ctx: Context, sender: str, msg: Transaction):
        if msg.seller == agent.name:
            agent.energy -= msg.amount
            agent.earnings += msg.amount * msg.price
            ctx.logger.info(f"Sold {msg.amount:.2f} units at {msg.price:.2f} per unit. Total earnings: {agent.earnings:.2f}")

def setup_consumer_agent(agent: ConsumerAgent):
    @agent.on_interval(period=90.0)
    async def calculate_energy_need(ctx: Context):
        timestamp = pd.Timestamp.now()
        last_hour_consumption = agent.energy_needed  # Use the current need as last hour's consumption
        last_day_consumption = agent.max_consumption  # Use max_consumption as a proxy for last day's consumption
        agent.energy_needed = predict_price("energy_consumption", timestamp, last_hour_consumption, last_day_consumption)
        ctx.logger.info(f"Energy needed: {agent.energy_needed:.2f} units")


    @agent.on_interval(period=180.0)
    async def create_request(ctx: Context):
        if agent.energy_needed > 0:
            timestamp = pd.Timestamp.now()
            last_hour_consumption = agent.energy_needed
            last_day_consumption = agent.max_consumption
            amount = min(agent.energy_needed, predict_price("request_amount", timestamp, last_hour_consumption, last_day_consumption))
            max_price = predict_price("max_price", timestamp, last_hour_consumption, last_day_consumption)
            request = EnergyRequest(consumer_id=agent.name, amount=amount, max_price=max_price)
            await ctx.send("market", request)
            ctx.logger.info(f"Sent request: {amount:.2f} units at max {max_price:.2f} per unit")

    @agent.on_message(model=Transaction)
    async def handle_transaction(ctx: Context, sender: str, msg: Transaction):
        if msg.buyer == agent.name:
            agent.energy_needed -= msg.amount
            agent.expenses += msg.amount * msg.price
            ctx.logger.info(f"Bought {msg.amount:.2f} units at {msg.price:.2f} per unit. Total expenses: {agent.expenses:.2f}")

def setup_market_agent(agent: MarketAgent):
    @agent.on_message(model=EnergyOffer)
    async def handle_offer(ctx: Context, sender: str, msg: EnergyOffer):
        agent.offers.append(msg)
        ctx.logger.info(f"Received offer from {msg.producer_id}: {msg.amount:.2f} units at {msg.price:.2f}")

    @agent.on_message(model=EnergyRequest)
    async def handle_request(ctx: Context, sender: str, msg: EnergyRequest):
        agent.requests.append(msg)
        ctx.logger.info(f"Received request from {msg.consumer_id}: {msg.amount:.2f} units at max {msg.max_price:.2f}")

    @agent.on_interval(period=300.0)
    async def match_offers_and_requests(ctx: Context):
        agent.offers.sort(key=lambda x: x.price)
        agent.requests.sort(key=lambda x: x.max_price, reverse=True)

        transactions = []

        for request in agent.requests:
            for offer in agent.offers:
                if offer.amount > 0 and request.amount > 0 and offer.price <= request.max_price:
                    trade_amount = min(offer.amount, request.amount)
                    trade_price = (offer.price + request.max_
[truncated — 2117 more characters]
```

### scrapped/energy_trading_sim.py

```python
import random
import time
from dataclasses import dataclass

@dataclass
class EnergyOffer:
    producer: str
    amount: float
    price: float

@dataclass
class EnergyRequest:
    consumer: str
    amount: float
    max_price: float

class Producer:
    def __init__(self, name, capacity):
        self.name = name
        self.capacity = capacity
        self.energy = 0
        self.balance = 0

    def generate_energy(self):
        self.energy = random.uniform(0, self.capacity)
        return self.energy

    def create_offer(self):
        amount = min(self.energy, random.uniform(0, self.energy))
        price = random.uniform(5, 15)
        return EnergyOffer(self.name, amount, price)

class Consumer:
    def __init__(self, name, max_consumption):
        self.name = name
        self.max_consumption = max_consumption
        self.energy_needed = 0
        self.balance = 1000  # Starting balance

    def calculate_energy_need(self):
        self.energy_needed = random.uniform(0, self.max_consumption)
        return self.energy_needed

    def create_request(self):
        amount = min(self.energy_needed, random.uniform(0, self.energy_needed))
        max_price = random.uniform(10, 20)
        return EnergyRequest(self.name, amount, max_price)

class EnergyMarket:
    def __init__(self):
        self.offers = []
        self.requests = []
        self.transactions = []

    def add_offer(self, offer):
        self.offers.append(offer)

    def add_request(self, request):
        self.requests.append(request)

    def match_offers_and_requests(self):
        for request in self.requests:
            for offer in self.offers:
                if offer.amount > 0 and request.amount > 0 and offer.price <= request.max_price:
                    trade_amount = min(offer.amount, request.amount)
                    self.transactions.append({
                        'seller': offer.producer,
                        'buyer': request.consumer,
                        'amount': trade_amount,
                        'price': offer.price
                    })
                    offer.amount -= trade_amount
                    request.amount -= trade_amount
        
        self.offers = [offer for offer in self.offers if offer.amount > 0]
        self.requests = [request for request in self.requests if request.amount > 0]

def simulate_energy_trading(producers, consumers, market, days):
    for day in range(days):
        print(f"Day {day + 1}")
        
        # Producers generate energy and create offers
        for producer in producers:
            energy_generated = producer.generate_energy()
            offer = producer.create_offer()
            market.add_offer(offer)
            print(f"{producer.name} generated {energy_generated:.2f} units and offered {offer.amount:.2f} units at {offer.price:.2f}")

        # Consumers calculate energy needs and create requests
        for consumer in consumers:
            energy_needed = consumer.calculate_energy_need()
            request = consumer.create_request()
            market.add_request(request)
            print(f"{consumer.name} needs {energy_needed:.2f} units and requested {request.amount:.2f} units at max {request.max_price:.2f}")

        # Match offers and requests
        market.match_offers_and_requests()

        # Process transactions
        for transaction in market.transactions:
            seller = next(p for p in producers if p.name == transaction['seller'])
            buyer = next(c for c in consumers if c.name == transaction['consumer'])
            amount = transaction['amount']
            price = transaction['price']
            total_cost = amount * price

            seller.balance += total_cost
            buyer.balance -= total_cost
            seller.energy -= amount
            buyer.energy_needed -= amount

            print(f"Transaction: {seller.name} sold {amount:.2f} units to {buyer.name} at {price:.2f} per unit")

        # Clear transactions for the next day
        market.transactions.clear()

        print("\n")
        time.sleep(1)  # Pause for 1 second between days

# Set up the simulation
producers = [Producer("SolarCo", 100), Producer("WindPower", 150)]
consumers = [Consumer("HomeTown", 80), Consumer("FactoryInc", 200)]
market = EnergyMarket()

# Run the simulation
simulate_energy_trading(producers, consumers, market, 5)
```

[16 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]