-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Implement Agent & Agent001 for signal generation package
- Loading branch information
1 parent
7f6c2cd
commit f271d11
Showing
9 changed files
with
366 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .agent import * |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import asyncio | ||
from abc import ABC, abstractmethod | ||
from typing import List, Optional | ||
from packages.itbot.itbot import Signal | ||
import threading | ||
import logging | ||
from trade_flow.common.logging import Logger | ||
|
||
|
||
class Agent(ABC): | ||
""" | ||
Abstract base class for agent interfaces responsible for loading trained models and generating trading signals. | ||
The agent continuously waits for data and sends signals asynchronously as an event-driven program. | ||
""" | ||
|
||
def __init__(self, logger: Optional[Logger] = None): | ||
# Set up logging | ||
self.logger = logger or Logger(name="it_bot", log_level=logging.DEBUG, filename="ITBot.log") | ||
|
||
self.model = None | ||
self.signals_queue = asyncio.Queue() | ||
self.loop = None | ||
|
||
@abstractmethod | ||
def load_model(self, model_path: str) -> None: | ||
""" | ||
Load the trained model from the specified path. | ||
Args: | ||
model_path (str): The file path of the trained model. | ||
""" | ||
pass | ||
|
||
@abstractmethod | ||
async def generate_signals(self, data: dict) -> List[Signal]: | ||
""" | ||
Asynchronously generate trading signals using the loaded model and input data. | ||
Args: | ||
data (dict): The data for the agent to make decisions. | ||
Returns: | ||
List[Signal]: A list of trading signals generated by the model. | ||
""" | ||
pass | ||
|
||
async def add_data(self, data: dict) -> None: | ||
""" | ||
Add data to the agent to trigger signal generation. This acts as an event to push new data. | ||
Args: | ||
data (dict): The data for generating signals. | ||
""" | ||
await self.signals_queue.put(data) | ||
|
||
async def send_signals(self, signals: List[Signal]) -> None: | ||
""" | ||
Asynchronously send the generated signals to ITBot. | ||
Args: | ||
signals (List[Signal]): The generated signals to be sent. | ||
""" | ||
for signal in signals: | ||
self.logger.info(f"Sending signal: {signal}") | ||
await asyncio.sleep(0.1) | ||
|
||
async def _run_tasks(self) -> None: | ||
""" | ||
Asynchronously wait for data, generate signals, and send them. This keeps running in the event loop. | ||
""" | ||
while True: | ||
data = await self.signals_queue.get() | ||
signals = await self.generate_signals(data) | ||
await self.send_signals(signals) | ||
|
||
def _start_event_loop(self) -> None: | ||
""" | ||
Start the event loop in the background using `asyncio.create_task`. | ||
This allows the agent to run without blocking the main thread. | ||
""" | ||
self.loop = asyncio.new_event_loop() | ||
asyncio.set_event_loop(self.loop) | ||
self.loop.create_task(self._run_tasks()) # Schedule _run_tasks in the background | ||
self.loop.run_forever() # Keep the event loop running indefinitely | ||
|
||
def run(self) -> None: | ||
""" | ||
Start the event loop in a separate thread, allowing the agent to process signals in the background. | ||
""" | ||
self.logger.debug("Running Agent") | ||
thread = threading.Thread(target=self._start_event_loop, daemon=True) | ||
thread.start() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import asyncio | ||
import os | ||
from typing import List, Optional | ||
from packages.itbot.itbot import Signal | ||
from packages.itbot.agents.agent import Agent | ||
from trade_flow.common.logging import Logger | ||
|
||
|
||
class Agent001(Agent): | ||
""" | ||
Example agent that implements Agent, for loading a model, generating signals, and sending them to ITBot. | ||
""" | ||
|
||
def __init__(self, logger: Optional[Logger] = None): | ||
super().__init__(logger) | ||
self.model = None | ||
|
||
def load_model(self, model_path: str) -> None: | ||
""" | ||
Load the trained model from the specified path. | ||
""" | ||
if os.path.exists(model_path): | ||
# Dummy model loading for demonstration purposes | ||
self.model = f"Loaded model from {model_path}" | ||
self.logger.info(f"Model loaded from {model_path}") | ||
else: | ||
raise FileNotFoundError(f"Model file {model_path} not found.") | ||
|
||
async def generate_signals(self, data: dict) -> List[Signal]: | ||
""" | ||
Asynchronously generate trading signals using the loaded model based on the data. | ||
Args: | ||
data: Data from the environment to generate signals. | ||
Returns: | ||
List[Signal]: A list of generated trading signals. | ||
""" | ||
if self.model is None: | ||
raise ValueError("Model is not loaded. Please load the model first.") | ||
|
||
# Simulate signal generation delay | ||
await asyncio.sleep(1) | ||
|
||
# Example signals based on input data | ||
signals = [ | ||
Signal( | ||
symbol="BTCUSD", | ||
price=data["price"], | ||
score=data["score"], | ||
trend="↑", | ||
zone="Buy Zone", | ||
trade_type="Buy", | ||
), | ||
Signal( | ||
symbol="ETHUSD", | ||
price=data["price"] * 0.05, | ||
score=data["score"] - 0.2, | ||
trend="↓", | ||
zone="Sell Zone", | ||
trade_type="Sell", | ||
), | ||
] | ||
return signals | ||
|
||
async def send_signals(self) -> None: | ||
""" | ||
Asynchronously send the generated signals to ITBot for further processing and forwarding to MT5. | ||
""" | ||
while True: | ||
# Wait for new data to be added | ||
data = await self.signals_queue.get() | ||
|
||
# Generate signals asynchronously based on new data | ||
signals = await self.generate_signals(data) | ||
|
||
for signal in signals: | ||
# Forward the signal to ITBot's queue | ||
self.trader.execute_trade(signal) | ||
self.logger.info(f"Signal sent to ITBot: {signal}") | ||
|
||
def run(self): | ||
""" | ||
Run the agent in the background, processing data and sending signals. | ||
""" | ||
super().run() # Starts the event loop and processes tasks |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.