JuanFuriaz commited on
Commit
80ac665
·
verified ·
1 Parent(s): 725cb3b

Upload folder using huggingface_hub

Browse files
__pycache__/strategy_generator.cpython-311.pyc ADDED
Binary file (8.38 kB). View file
 
__pycache__/utils.cpython-311.pyc CHANGED
Binary files a/__pycache__/utils.cpython-311.pyc and b/__pycache__/utils.cpython-311.pyc differ
 
app.py CHANGED
@@ -4,6 +4,7 @@ import os
4
  os.environ.setdefault("MPLBACKEND", "Agg")
5
  import io
6
  import sys
 
7
  from datetime import datetime
8
  import pandas as pd
9
  import yfinance as yf
@@ -11,8 +12,7 @@ from dotenv import load_dotenv
11
  import gradio as gr
12
  import yaml
13
  import traceback
14
- from strategy_generator_agent import stream_manager
15
- from strategy_generator_agent import LLM_MODEL
16
  from utils import (
17
  write_output,
18
  _to_float_or_default,
@@ -111,6 +111,17 @@ final_value, total_return, tmp_img, df_trades, df_transactions = run_bt(
111
  return output.getvalue(), tmp_img, df_trades, df_transactions
112
 
113
 
 
 
 
 
 
 
 
 
 
 
 
114
  def run_gradio_app():
115
  """ Run the Gradio app for strategy generation and backtesting. """
116
  market_list = list[market_to_ticker](market_to_ticker.keys())
@@ -141,7 +152,12 @@ def run_gradio_app():
141
  adjust_prices_in = gr.Checkbox(label="Use adjusted (dividend/split) prices", value=config.get("adjust_prices", True))
142
  #period = gr.Dropdown(["30d", "10d", "60d"], value="60d", label="Period")
143
  with gr.Row():
144
- py_out = gr.TextArea(label="Python result:", elem_classes=["python"])
 
 
 
 
 
145
  with gr.Tab("Charts"):
146
  image_output = gr.Gallery(
147
  label="Charts",
@@ -203,6 +219,11 @@ def run_gradio_app():
203
  inputs=[trades_df],
204
  outputs=[trades_csv]
205
  )
 
 
 
 
 
206
  ui.launch(inbrowser=True, share=False, debug=True)
207
 
208
  if __name__ == "__main__":
 
4
  os.environ.setdefault("MPLBACKEND", "Agg")
5
  import io
6
  import sys
7
+ import tempfile
8
  from datetime import datetime
9
  import pandas as pd
10
  import yfinance as yf
 
12
  import gradio as gr
13
  import yaml
14
  import traceback
15
+ from strategy_generator import stream_manager
 
16
  from utils import (
17
  write_output,
18
  _to_float_or_default,
 
111
  return output.getvalue(), tmp_img, df_trades, df_transactions
112
 
113
 
114
+ def save_strategy_to_file(code_text: str):
115
+ """Persist generated strategy code into a temp file Gradio can expose."""
116
+ if not code_text:
117
+ return None
118
+ tmp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".py", prefix="strategy_")
119
+ tmp_file.write(code_text.encode("utf-8"))
120
+ tmp_file.flush()
121
+ tmp_file.close()
122
+ return tmp_file.name
123
+
124
+
125
  def run_gradio_app():
126
  """ Run the Gradio app for strategy generation and backtesting. """
127
  market_list = list[market_to_ticker](market_to_ticker.keys())
 
152
  adjust_prices_in = gr.Checkbox(label="Use adjusted (dividend/split) prices", value=config.get("adjust_prices", True))
153
  #period = gr.Dropdown(["30d", "10d", "60d"], value="60d", label="Period")
154
  with gr.Row():
155
+ with gr.Column(scale=6):
156
+ py_out = gr.TextArea(label="Python result:", elem_classes=["python"])
157
+ with gr.Column(scale=1):
158
+ with gr.Group():
159
+ download_strategy_btn = gr.Button("Download Strategy Code", variant="primary")
160
+ strategy_file = gr.File(label="Strategy File", visible=True, interactive=False)
161
  with gr.Tab("Charts"):
162
  image_output = gr.Gallery(
163
  label="Charts",
 
219
  inputs=[trades_df],
220
  outputs=[trades_csv]
221
  )
222
+ download_strategy_btn.click(
223
+ save_strategy_to_file,
224
+ inputs=[code],
225
+ outputs=[strategy_file]
226
+ )
227
  ui.launch(inbrowser=True, share=False, debug=True)
228
 
229
  if __name__ == "__main__":
strategy_generator.py ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import anthropic
2
+ import os
3
+ from dotenv import load_dotenv
4
+ import yaml
5
+ from openai import OpenAI
6
+ from huggingface_hub import InferenceClient
7
+
8
+
9
+ load_dotenv(override=True)
10
+ os.environ['OPENAI_API_KEY'] = os.getenv('OPENAI_API_KEY')
11
+ os.environ['ANTHROPIC_API_KEY'] = os.getenv('ANTHROPIC_API_KEY')
12
+ google_api_key = os.getenv('GOOGLE_API_KEY')
13
+ deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')
14
+ grok_api_key = os.getenv("XAI_API_KEY")
15
+
16
+ with open('config/var_dev.yaml', 'r') as f:
17
+ config = yaml.safe_load(f)
18
+
19
+
20
+ # Logging stuff
21
+ if config["local"]:
22
+ hf_token = os.getenv('HF_TOKEN') # Sign in to HuggingFace Hub
23
+ else:
24
+ hf_token = None
25
+ #huggingface_hub.login(hf_token)
26
+ # Initialize clients
27
+ openai = OpenAI()
28
+ deepseek_api= OpenAI(
29
+ api_key=deepseek_api_key,
30
+ base_url="https://api.deepseek.com"
31
+ )
32
+ gemini_api = OpenAI(
33
+ api_key=google_api_key,
34
+ base_url="https://generativelanguage.googleapis.com/v1beta/openai/"
35
+ )
36
+ grok_api = OpenAI(api_key=grok_api_key, base_url="https://api.x.ai/v1")
37
+ claude = anthropic.Anthropic()
38
+ client = InferenceClient() # For HuggingFace Inference API
39
+
40
+ LLM_MODEL = None
41
+
42
+ def user_prompt_for(user_msg):
43
+ return f"""
44
+ Trading strategy description:
45
+ \"\"\"{user_msg}\"\"\"
46
+
47
+ Task:
48
+ - Convert the description into executable Python code.
49
+ - Use only the library {config["api_fin"]}.
50
+ - Respond only with valid Python code, following Python best practices
51
+ """
52
+
53
+ example_1= f'''
54
+ # User prompt:
55
+ # "Go long when the 10-period SMA crosses above the 100-period SMA,
56
+ # and exit when the 10-period SMA crosses below the 100-period SMA."
57
+
58
+
59
+ # Generated Python code:
60
+
61
+ import backtrader as bt
62
+ class SmaCross(bt.Strategy):
63
+ """
64
+ Simple moving average crossover strategy.
65
+ Buy when fast SMA crosses above slow SMA.
66
+ Sell when fast SMA crosses below slow SMA.
67
+ """
68
+ params = dict(pfast=10, pslow=100)
69
+
70
+ def __init__(self):
71
+ self.sma_fast = bt.ind.SMA(period=self.p.pfast)
72
+ self.sma_slow = bt.ind.SMA(period=self.p.pslow)
73
+ self.crossover = bt.ind.CrossOver(self.sma_fast, self.sma_slow)
74
+
75
+ def next(self):
76
+ if not self.position:
77
+ if self.crossover > 0: # Golden cross
78
+ self.buy()
79
+ elif self.crossover < 0: # Death cross
80
+ self.close()
81
+
82
+ # Initialize Cerebro
83
+ cerebro = bt.Cerebro()
84
+ cerebro.addstrategy(SmaCross, pfast=10, pslow=100)
85
+ '''
86
+ list_of_pyclasses = [example_1]
87
+ system_message = f'''
88
+ You are a financial assistant specialized in transforming natural language descriptions of trading strategies into clean, production-ready Python code.
89
+
90
+ Guidelines:
91
+ - Use only the library {config["api_fin"]}.
92
+ - Always create a class with the abreviation of the strategy with the form `NameOfStrategy(bt.Strategy)`.
93
+ - Implement strategy logic in `__init__` (indicators/signals) and `next()` (trade execution).
94
+ - Implement the strategy for this intervall of time {config["interval"]}
95
+ - Finish with initializing the strategy in Cerebro:
96
+ cerebro = bt.Cerebro()
97
+ cerebro.addstrategy(MyStrategy, param1=value, param2=value)
98
+ - Keep code minimal, clear, and follow Java best practices (PEP8, clear naming, modularity).
99
+ - If a strategy cannot be implemented with {config["api_fin"]}, respond with: "Unable to implement with {config["api_fin"]}."
100
+ - If used any addional libraries, add it in the code: import MyUsedLibrary
101
+ - If you don't know the answer, just say that you don't know, don't try to make up an answer.
102
+
103
+
104
+ Example(s) of transformation from user prompt of Python code: \n
105
+ '''
106
+ for pyclass in list_of_pyclasses:
107
+ system_message += pyclass
108
+ # Messages in Openai format
109
+ def messages_for(user_msg):
110
+ return [
111
+ {"role": "system", "content": system_message},
112
+ {"role": "user", "content": user_prompt_for(user_msg)}
113
+ ]
114
+
115
+
116
+ def stream_llms(user_msg, typ_llm="gpt"):
117
+ """ Stream responses from different LLMs based on user message and selected model. """
118
+ global LLM_MODEL
119
+ llm_key = typ_llm.lower()
120
+ model_overrides = {
121
+ "deepseek": ("DEEPSEEK_MODEL", config.get("deepseek_model")),
122
+ "gimini": ("GEMINI_MODEL", config.get("gemini_model")),
123
+ "grok4": ("GROK4_MODEL", config.get("grok4_model")),
124
+ "claude": ("CLAUDE_MODEL", config.get("claude_model")),
125
+ "gpt": ("OPENAI_MODEL", config.get("openai_model")),
126
+ }
127
+ if llm_key not in model_overrides:
128
+ raise ValueError("Unknown model")
129
+ env_var, default_model = model_overrides[llm_key]
130
+ if not default_model:
131
+ raise KeyError(f"Missing default model configuration for '{llm_key}'")
132
+ selected_model = os.getenv(env_var) or default_model
133
+ LLM_MODEL = selected_model
134
+ messages = messages_for(user_msg)
135
+
136
+ if llm_key == "deepseek":
137
+ stream = deepseek_api.chat.completions.create(
138
+ model=selected_model,
139
+ messages=messages,
140
+ stream=True
141
+ )
142
+ elif llm_key == "gimini":
143
+ stream = gemini_api.chat.completions.create(
144
+ model=selected_model,
145
+ messages=messages,
146
+ stream=True
147
+ )
148
+ elif llm_key == "grok4":
149
+ stream = grok_api.chat.completions.create(
150
+ model=selected_model,
151
+ messages=messages,
152
+ stream= True
153
+ )
154
+ elif llm_key == "claude":
155
+ stream = claude.messages.stream(
156
+ model=selected_model,
157
+ max_tokens=2000,
158
+ system=messages[0]['content'],
159
+ messages=[messages[1]],
160
+ )
161
+ elif llm_key == "gpt":
162
+ stream = openai.chat.completions.create(model=selected_model, messages=messages, stream=True)
163
+ else:
164
+ raise ValueError("Unknown model")
165
+
166
+ reply = f"# Model {LLM_MODEL}\n"
167
+
168
+ if typ_llm.lower() == "claude":
169
+ with stream as stream_clde:
170
+ for fragment in stream_clde.text_stream:
171
+ reply += fragment
172
+ yield reply.replace("```python\n","").replace("```","")
173
+
174
+ else:
175
+ for chunk in stream:
176
+ if chunk and chunk.choices:
177
+ fragment = chunk.choices[0].delta.content or ""
178
+ reply += fragment
179
+ yield reply.replace("```python\n","").replace("```","")
180
+
181
+
182
+
183
+ def stream_manager(user_msg, model):
184
+ """ Streaming manager for different LLMs based on user message and selected model. """
185
+ result = stream_llms(user_msg, model)
186
+ for stream_so_far in result:
187
+ yield stream_so_far
188
+