| import anthropic |
| import os |
| from dotenv import load_dotenv |
| import yaml |
| from openai import OpenAI |
| from huggingface_hub import InferenceClient |
|
|
|
|
| load_dotenv(override=True) |
| os.environ['OPENAI_API_KEY'] = os.getenv('OPENAI_API_KEY') |
| os.environ['ANTHROPIC_API_KEY'] = os.getenv('ANTHROPIC_API_KEY') |
| google_api_key = os.getenv('GOOGLE_API_KEY') |
| deepseek_api_key = os.getenv('DEEPSEEK_API_KEY') |
| grok_api_key = os.getenv("XAI_API_KEY") |
|
|
| with open('config/var_dev.yaml', 'r') as f: |
| config = yaml.safe_load(f) |
| |
|
|
| |
| if config["local"]: |
| hf_token = os.getenv('HF_TOKEN') |
| else: |
| hf_token = None |
| |
| |
| openai = OpenAI() |
| deepseek_api= OpenAI( |
| api_key=deepseek_api_key, |
| base_url="https://api.deepseek.com" |
| ) |
| gemini_api = OpenAI( |
| api_key=google_api_key, |
| base_url="https://generativelanguage.googleapis.com/v1beta/openai/" |
| ) |
| grok_api = OpenAI(api_key=grok_api_key, base_url="https://api.x.ai/v1") |
| claude = anthropic.Anthropic() |
| client = InferenceClient() |
|
|
| LLM_MODEL = None |
|
|
| def user_prompt_for(user_msg): |
| return f""" |
| Trading strategy description: |
| \"\"\"{user_msg}\"\"\" |
| |
| Task: |
| - Convert the description into executable Python code. |
| - Use only the library {config["api_fin"]}. |
| - Respond only with valid Python code, following Python best practices |
| """ |
|
|
| example_1= f''' |
| # User prompt: |
| # "Go long when the 10-period SMA crosses above the 100-period SMA, |
| # and exit when the 10-period SMA crosses below the 100-period SMA." |
| |
| |
| # Generated Python code: |
| |
| import backtrader as bt |
| class SmaCross(bt.Strategy): |
| """ |
| Simple moving average crossover strategy. |
| Buy when fast SMA crosses above slow SMA. |
| Sell when fast SMA crosses below slow SMA. |
| """ |
| params = dict(pfast=10, pslow=100) |
| |
| def __init__(self): |
| self.sma_fast = bt.ind.SMA(period=self.p.pfast) |
| self.sma_slow = bt.ind.SMA(period=self.p.pslow) |
| self.crossover = bt.ind.CrossOver(self.sma_fast, self.sma_slow) |
| |
| def next(self): |
| if not self.position: |
| if self.crossover > 0: # Golden cross |
| self.buy() |
| elif self.crossover < 0: # Death cross |
| self.close() |
| |
| # Initialize Cerebro |
| cerebro = bt.Cerebro() |
| cerebro.addstrategy(SmaCross, pfast=10, pslow=100) |
| ''' |
| list_of_pyclasses = [example_1] |
| system_message = f''' |
| You are a financial assistant specialized in transforming natural language descriptions of trading strategies into clean, production-ready Python code. |
| |
| Guidelines: |
| - Use only the library {config["api_fin"]}. |
| - Always create a class with the abreviation of the strategy with the form `NameOfStrategy(bt.Strategy)`. |
| - Implement strategy logic in `__init__` (indicators/signals) and `next()` (trade execution). |
| - Implement the strategy for this intervall of time {config["interval"]} |
| - Finish with initializing the strategy in Cerebro: |
| cerebro = bt.Cerebro() |
| cerebro.addstrategy(MyStrategy, param1=value, param2=value) |
| - Keep code minimal, clear, and follow Java best practices (PEP8, clear naming, modularity). |
| - If a strategy cannot be implemented with {config["api_fin"]}, respond with: "Unable to implement with {config["api_fin"]}." |
| - If used any addional libraries, add it in the code: import MyUsedLibrary |
| - If you don't know the answer, just say that you don't know, don't try to make up an answer. |
| |
| |
| Example(s) of transformation from user prompt of Python code: \n |
| ''' |
| for pyclass in list_of_pyclasses: |
| system_message += pyclass |
| |
| def messages_for(user_msg): |
| return [ |
| {"role": "system", "content": system_message}, |
| {"role": "user", "content": user_prompt_for(user_msg)} |
| ] |
| |
|
|
| def stream_llms(user_msg, typ_llm="gpt"): |
| """ Stream responses from different LLMs based on user message and selected model. """ |
| global LLM_MODEL |
| llm_key = typ_llm.lower() |
| model_overrides = { |
| "deepseek": ("DEEPSEEK_MODEL", config.get("deepseek_model")), |
| "gimini": ("GEMINI_MODEL", config.get("gemini_model")), |
| "grok4": ("GROK4_MODEL", config.get("grok4_model")), |
| "claude": ("CLAUDE_MODEL", config.get("claude_model")), |
| "gpt": ("OPENAI_MODEL", config.get("openai_model")), |
| } |
| if llm_key not in model_overrides: |
| raise ValueError("Unknown model") |
| env_var, default_model = model_overrides[llm_key] |
| if not default_model: |
| raise KeyError(f"Missing default model configuration for '{llm_key}'") |
| selected_model = os.getenv(env_var) or default_model |
| LLM_MODEL = selected_model |
| messages = messages_for(user_msg) |
|
|
| if llm_key == "deepseek": |
| stream = deepseek_api.chat.completions.create( |
| model=selected_model, |
| messages=messages, |
| stream=True |
| ) |
| elif llm_key == "gimini": |
| stream = gemini_api.chat.completions.create( |
| model=selected_model, |
| messages=messages, |
| stream=True |
| ) |
| elif llm_key == "grok4": |
| stream = grok_api.chat.completions.create( |
| model=selected_model, |
| messages=messages, |
| stream= True |
| ) |
| elif llm_key == "claude": |
| stream = claude.messages.stream( |
| model=selected_model, |
| max_tokens=2000, |
| system=messages[0]['content'], |
| messages=[messages[1]], |
| ) |
| elif llm_key == "gpt": |
| stream = openai.chat.completions.create(model=selected_model, messages=messages, stream=True) |
| else: |
| raise ValueError("Unknown model") |
| |
| reply = f"# Model {LLM_MODEL}\n" |
| |
| if typ_llm.lower() == "claude": |
| with stream as stream_clde: |
| for fragment in stream_clde.text_stream: |
| reply += fragment |
| yield reply.replace("```python\n","").replace("```","") |
|
|
| else: |
| for chunk in stream: |
| if chunk and chunk.choices: |
| fragment = chunk.choices[0].delta.content or "" |
| reply += fragment |
| yield reply.replace("```python\n","").replace("```","") |
|
|
|
|
|
|
| def stream_manager(user_msg, model): |
| """ Streaming manager for different LLMs based on user message and selected model. """ |
| result = stream_llms(user_msg, model) |
| for stream_so_far in result: |
| yield stream_so_far |
|
|
|
|