Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ eth-account==0.11.0
web3==6.20.1

# ========== Data & Analysis ==========
pandas==2.1.4
numpy==1.26.2
pandas-ta==0.3.14b0
TA-Lib==0.4.32 # Technical indicators
pandas>=2.3.2
numpy==2.2.6
pandas-ta==0.4.71b0
# TA-Lib==0.4.32 # Technical indicators
Backtesting==0.3.3 # Backtesting framework
yfinance==0.2.43 # For fetching Yahoo Finance data

Expand Down
8 changes: 8 additions & 0 deletions spec/constitution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Constitution for Low-Latency Spec-Driven Trading Agents

## Core Principles

1. **Speed Over Sentiment:** All agent decisions must prioritize signal latency over sentiment analysis for trade horizons under 1-hour.
2. **Quantitative Rigor:** Specifications must be defined as "Market Micro-Structure Exploits" rather than "User Stories."
3. **Specialized Roles:** Agents will have narrowly defined roles to ensure low-latency, specialized processing.
4. **Traceability:** All trading decisions must be traceable back to a specific specification.
73 changes: 73 additions & 0 deletions src/data/tick_collector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""
Tick Data Collector

This script connects to the HyperLiquid WebSocket API to collect real-time tick data.
"""

import websocket
import json
import threading

class TickCollector:
def __init__(self, symbol):
self.symbol = symbol
self.ws = None
self.latest_tick = None
self.is_connected = False
websocket.enableTrace(True)

def on_message(self, ws, message):
self.latest_tick = json.loads(message)
print(f"New tick received: {self.latest_tick}")

def on_error(self, ws, error):
print(f"WebSocket Error: {error}")
self.is_connected = False

def on_close(self, ws, close_status_code, close_msg):
print("### WebSocket closed ###")
self.is_connected = False

def on_open(self, ws):
print("### WebSocket opened ###")
self.is_connected = True
self.ws.send(json.dumps({
"method": "subscribe",
"subscription": {"type": "trades", "coin": self.symbol}
}))

def start(self):
"""Starts the WebSocket connection in a new thread."""
self.ws = websocket.WebSocketApp("wss://api.hyperliquid.xyz/ws",
on_message=self.on_message,
on_error=self.on_error,
on_close=self.on_close)
self.ws.on_open = self.on_open

# Run the WebSocket in a separate thread to avoid blocking
wst = threading.Thread(target=self.ws.run_forever)
wst.daemon = True
wst.start()

def get_latest_tick(self):
"""Returns the latest tick received from the WebSocket."""
return self.latest_tick

def stop(self):
"""Closes the WebSocket connection."""
if self.ws:
self.ws.close()
self.is_connected = False
print("WebSocket connection closed.")

if __name__ == "__main__":
# Example usage
collector = TickCollector(symbol='BTC')
collector.start()

# Keep the main thread alive to see the ticks coming in
try:
while True:
pass
except KeyboardInterrupt:
collector.stop()
28 changes: 28 additions & 0 deletions src/spec_driven_agents/async_swarm_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""
Asynchronous Swarm Agent

This agent is responsible for querying multiple AI models asynchronously.
"""

import asyncio
import aiohttp

class AsyncSwarmAgent:
def __init__(self, model_urls):
self.model_urls = model_urls

async def fetch(self, session, url, prompt):
"""
Fetches a response from a single AI model.
"""
async with session.post(url, json={'prompt': prompt}) as response:
return await response.json()

async def query(self, prompt):
"""
Queries all AI models asynchronously and returns their responses.
"""
async with aiohttp.ClientSession() as session:
tasks = [self.fetch(session, url, prompt) for url in self.model_urls]
responses = await asyncio.gather(*tasks)
return responses
28 changes: 28 additions & 0 deletions src/spec_driven_agents/decision_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""
Decision Agent

This agent is responsible for aggregating signals from other specialized agents
and making a final trading decision.
"""

from src.models.model_factory import model_factory

class DecisionAgent:
def __init__(self, model_type='gemini', model_name='gemini-flash'):
self.model = model_factory.get_model(model_type, model_name)

def make_decision(self, indicator_signals, pattern_analysis):
"""
Makes a trading decision based on the provided signals.
"""
prompt = f"""
Given the following signals, make a trading decision (BUY, SELL, or HOLD).

Indicator Signals:
{indicator_signals}

Pattern Analysis:
{pattern_analysis}
"""
response = self.model.generate_response(prompt)
return response
22 changes: 22 additions & 0 deletions src/spec_driven_agents/drl_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""
Deep Reinforcement Learning (DRL) Agent

This agent will be responsible for learning and executing trading strategies using DRL.
This is a placeholder for now and will be implemented in a future iteration.
"""

class DRLAgent:
def __init__(self):
pass

def train(self):
"""
Trains the DRL agent.
"""
pass

def predict(self, state):
"""
Makes a prediction based on the current state.
"""
pass
29 changes: 29 additions & 0 deletions src/spec_driven_agents/indicator_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
"""
Indicator Agent

This agent is responsible for calculating low-latency technical indicators.
"""

import pandas as pd
import pandas_ta as ta

class IndicatorAgent:
def __init__(self):
pass

def calculate_rsi(self, data, period=14):
"""Calculates the Relative Strength Index (RSI)"""
return ta.rsi(data['close'], length=period)

def calculate_rate_of_change(self, data, period=14):
"""Calculates the Rate of Change (ROC)"""
roc = ((data['close'] - data['close'].shift(period)) / data['close'].shift(period)) * 100
return roc

def run(self, data):
"""Calculates all indicators and returns them as a dictionary"""
indicators = {
'rsi': self.calculate_rsi(data),
'roc': self.calculate_rate_of_change(data)
}
return indicators
42 changes: 42 additions & 0 deletions src/spec_driven_agents/lob_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""
LOB (Limit Order Book) Agent

This agent is responsible for managing trade-level risk by analyzing the Limit Order Book.
"""

from src.nice_funcs_hyperliquid import ask_bid

class LOBAgent:
def __init__(self):
pass

def get_order_book(self, symbol):
"""
Fetches the Limit Order Book for a given symbol.
"""
ask, bid, l2_data = ask_bid(symbol)
return l2_data

def analyze_order_book_imbalance(self, order_book):
"""
Analyzes the order book to identify imbalances.
"""
bids = order_book[0]
asks = order_book[1]

total_bid_volume = sum([float(bid['n']) for bid in bids])
total_ask_volume = sum([float(ask['n']) for ask in asks])

if total_bid_volume == 0:
return 0

imbalance = (total_bid_volume - total_ask_volume) / total_bid_volume
return imbalance

def run(self, symbol):
"""
Fetches and analyzes the order book for a given symbol.
"""
order_book = self.get_order_book(symbol)
imbalance = self.analyze_order_book_imbalance(order_book)
return imbalance
27 changes: 27 additions & 0 deletions src/spec_driven_agents/pattern_agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
"""
Pattern Agent

This agent is responsible for analyzing short-term candlestick patterns.
"""

import pandas as pd
from src.models.model_factory import model_factory

class PatternAgent:
def __init__(self, model_type='openai', model_name=None):
self.model = model_factory.get_model(model_type, model_name)

def analyze_patterns(self, data):
"""
Analyzes candlestick patterns using a multimodal LLM.
"""
# For now, we'll use a simplified approach.
# In the future, this will be replaced with a multimodal LLM.
prompt = f"""
Analyze the following candlestick data and identify any significant patterns.
Return a JSON object with the identified patterns and a confidence score.

{data.to_string()}
"""
response = self.model.generate_response(system_prompt="", user_content=prompt)
return response
21 changes: 21 additions & 0 deletions src/spec_driven_agents/test_agents.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""
Tests for the spec-driven agents.
"""

import pandas as pd
from src.spec_driven_agents.indicator_agent import IndicatorAgent

def test_rsi_calculation():
"""
Tests that the RSI is calculated correctly.
"""
data = {
'close': [
44.34, 44.09, 44.15, 43.61, 44.33, 44.83, 45.10, 45.42, 45.84, 46.08,
45.89, 46.03, 45.61, 46.28, 46.28, 46.00, 46.03, 46.41, 46.22, 45.64
]
}
df = pd.DataFrame(data)
agent = IndicatorAgent()
rsi = agent.calculate_rsi(df, period=14)
assert round(rsi.iloc[-1], 2) == 43.20
Loading