Skip to content

Commit 093543f

Browse files
authored
feat: change predefined signal creation to REPL-based dynamic creation (#16)
1 parent 71302b7 commit 093543f

60 files changed

Lines changed: 6981 additions & 16240 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ INVESTMENT_INITIAL_CAPITAL=10000
1313
# Set true only to launch the Agent Framework Dev UI instead of running the workflow.
1414
LAUNCH_DEV_UI=false
1515

16-
# Azure OpenAI (API key auth — alternative to Entra ID above)
17-
# Uncomment and set these if using api_key= instead of credential=
16+
# Optional direct Azure OpenAI connection for the Semantic Kernel workflow.
17+
# Without these values, it reuses AZURE_AI_PROJECT_ENDPOINT and the Foundry model above.
1818
# AZURE_OPENAI_ENDPOINT=https://<resource>.openai.azure.com/
19-
# AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME=gpt-4o
19+
# AZURE_OPENAI_CHAT_DEPLOYMENT_NAME=gpt-5.6-terra
2020
# AZURE_OPENAI_API_VERSION=2025-01-01-preview
2121
# AZURE_OPENAI_API_KEY=

README.md

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
# 💸 Investment Agent Patterns
1010

11-
This project shows how to use Microsoft Agent Framework for stock-market research. It downloads past prices, creates signals, tests simple strategies, and saves the results.
11+
This project shows how to use Microsoft Agent Framework for stock-market research. Agents download past prices, write and execute a technical-analysis signal script, test the resulting strategy, and save the results.
1212

1313
> [!NOTE]
1414
> Recommended first: Microsoft Agent Framework. It combines ideas from AutoGen and Semantic Kernel.
@@ -43,50 +43,56 @@ On PowerShell, use `Copy-Item .env.example .env` to copy the settings file. Then
4343
|---|---|
4444
| `AZURE_AI_PROJECT_ENDPOINT` | Address of the Azure AI Foundry project used by the main workflow. |
4545
| `AZURE_AI_MODEL_DEPLOYMENT_NAME` | Name of the chat model deployed in that project. |
46+
| `AZURE_OPENAI_ENDPOINT` | Optional direct Azure OpenAI endpoint for the Semantic Kernel workflow; otherwise it uses the Foundry project endpoint. |
47+
| `AZURE_OPENAI_CHAT_DEPLOYMENT_NAME` | Optional direct Azure OpenAI deployment for the Semantic Kernel workflow. |
4648
| `INVESTMENT_TICKER` | Stock symbol to study. The default is `MSFT`. |
4749
| `INVESTMENT_START_DATE`, `INVESTMENT_END_DATE` | First and last dates for the past-price data. |
4850
| `INVESTMENT_INITIAL_CAPITAL` | Pretend starting amount for the backtest. |
4951

5052
## Optional: Semantic Kernel variant
5153

52-
Use this command only when comparing the plugin-based variant. It creates the same type of charts, metrics, spreadsheets, and CSV files as the primary Agent Framework workflow, in its own output folder:
54+
Use this command only when comparing the plugin-based agent variant. It reuses the configured Foundry project and model by default, then creates charts, metrics, spreadsheets, CSVs, and the generated signal script in its own output folder:
5355

5456
```bash
5557
uv run python -m semantic_kernel.main
5658
```
5759

5860
## Sample research output
5961

60-
These files were created by the main Agent Framework workflow for `MSFT`, using the default date range and a pretend $10,000 starting balance. They are examples only. Results can change when the workflow is run again because market data changes.
62+
The following Agent Framework sample uses `MSFT` from 2020-01-01 through 2026-07-01 with a simulated $10,000 starting balance. It is historical research only; a later run can generate a different strategy and result.
6163

62-
### Input query
64+
### Input
6365

6466
```text
65-
Analyze MSFT from 2020-01-01 to 2026-07-01; generate MACD/RSI signals, backtest $10000, and report CAGR, total return, final value, drawdown, and Sharpe ratio.
67+
Analyze MSFT from 2020-01-01 to 2026-07-01. Develop one transparent technical-analysis signal strategy as Python code, execute it, backtest $10000, and report CAGR, total return, final value, drawdown, and Sharpe ratio.
6668
```
6769

68-
### Performance graph
70+
### Generated signal
6971

70-
The top line shows how the pretend portfolio value changed over time. The shaded lower chart shows drawdown: how far the portfolio fell from its highest value at each point.
72+
The sample agent generated a long-only trend-and-momentum signal using MSFT closing prices:
7173

72-
<img src="output/agent_framework/trix_ultimateoscillator_reversal/stock_plot.png" alt="TRIX and Ultimate Oscillator cumulative returns and drawdown" width="500">
74+
- **Buy:** the 50-day simple moving average is above the 200-day simple moving average and RSI(14) is above 50, after that combined condition was previously false.
75+
- **Sell:** the combined condition becomes false: the 50-day average is at or below the 200-day average, or RSI(14) is at or below 50.
76+
- **Hold:** no change in the combined condition.
77+
- **Execution convention:** a close-based condition affects the next session's return, reducing same-close look-ahead bias.
7378

74-
### Backtest metrics
79+
### Performance plot
80+
81+
The top panel shows cumulative strategy returns. The lower panel shows portfolio drawdown from its previous peak.
7582

76-
| Strategy | Cumulative return | CAGR | Maximum drawdown | Sharpe ratio | Final value |
77-
|---|---:|---:|---:|---:|---:|
78-
| [MACD and RSI momentum](output/agent_framework/macd_rsi_momentum/backtest_metrics.txt) | -2.82% | -0.91% | -26.51% | 0.02 | $9,717.67 |
79-
| [Moving-average trend](output/agent_framework/movingaverage_trend/backtest_metrics.txt) | -2.00% | -0.64% | -28.29% | 0.02 | $9,799.54 |
80-
| [TRIX and Ultimate Oscillator reversal](output/agent_framework/trix_ultimateoscillator_reversal/backtest_metrics.txt) | 9.60% | 2.96% | -25.73% | 0.29 | $10,959.96 |
83+
<img src="output/agent_framework/stock_plot.png" alt="Sample cumulative returns and drawdown for the Agent Framework research run" width="600">
8184

82-
- **Cumulative return** is the total percentage gained or lost over the whole test.
83-
- **CAGR** is the average yearly growth rate.
84-
- **Maximum drawdown** is the largest drop from a previous high point.
85-
- **Sharpe ratio** is one simple measure of return compared with day-to-day ups and downs; it is not a guarantee of quality.
85+
### Backtest metrics
8686

87-
### Summary example
87+
| Metric | Sample value |
88+
|---|---:|
89+
| [Cumulative return](output/agent_framework/backtest_metrics.txt) | 27.96% |
90+
| CAGR | 3.88% |
91+
| Maximum drawdown | -21.03% |
92+
| Sharpe ratio | 0.36 |
93+
| Final value | $12,796.05 |
8894

89-
> In this example run, the TRIX and Ultimate Oscillator strategy did better than the other two examples. A pretend $10,000 grew to $10,959.96, a 9.60% total gain. However, the portfolio also fell as much as 25.73% from an earlier high. One past result is not proof that a strategy will work in the future. Test it over other time periods and include trading fees, price changes during trades, and data checks before trusting the result.
95+
See the full [backtest workbook](output/agent_framework/backtest_results.xlsx), [generated signal script](output/agent_framework/generated_signal_strategy.py), and [validated signals](output/agent_framework/stock_signals.csv).
9096

9197
## Repository layout
9298

@@ -96,7 +102,7 @@ The top line shows how the pretend portfolio value changed over time. The shaded
96102
| [semantic_kernel](semantic_kernel) | The Semantic Kernel version of the research workflow. |
97103
| [autogen](autogen) | The AutoGen reference version, with its own Poetry environment. |
98104
| [agent_framework_patterns](agent_framework_patterns) | Thirty small Agent Framework examples for investment research. |
99-
| [tests](tests) | Offline tests for the Agent Framework patterns. |
105+
| [tests](tests) | Offline tests for Agent Framework patterns and the REPL contracts. |
100106
| [output](output) | Saved charts, metrics, and example pattern responses. |
101107
| [docs](docs) | Guides for each implementation and framework comparison. |
102108

@@ -106,12 +112,13 @@ The Agent Framework pattern tests run without Azure credentials or live market-d
106112

107113
```bash
108114
uv run ruff check agent_framework semantic_kernel agent_framework_patterns tests
109-
uv run pytest tests/agent_framework_patterns -q
115+
uv run pytest tests -q
110116
```
111117

112118
## Safety and limitations
113119

114120
- These results are for learning and research, not financial advice or a real trading system.
121+
- Both workflows execute model-authored Python to create signals. Their validation is not a security sandbox; run them only in an isolated development environment without credentials or production data.
115122
- Good results from the past do not mean the same strategy will work in the future.
116123
- The examples use public market data and simple rules. They leave out trading fees, price changes that happen while a trade is being made, taxes, careful handling of stock splits and dividends, and checks for an individual investor's needs.
117124
- Review AI responses, connected tools, and data licences before using this project outside a learning or research setting.

agent_framework/main.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ def task() -> str:
1515
start = os.getenv("INVESTMENT_START_DATE", "2020-01-01")
1616
end = os.getenv("INVESTMENT_END_DATE", "2026-07-01")
1717
capital = os.getenv("INVESTMENT_INITIAL_CAPITAL", "10000")
18-
return f"Analyze {ticker} from {start} to {end}; generate MACD/RSI signals, backtest ${capital}, and report CAGR, total return, final value, drawdown, and Sharpe ratio."
18+
return (
19+
f"Analyze {ticker} from {start} to {end}. Develop one transparent technical-analysis "
20+
f"signal strategy as Python code, execute it, backtest ${capital}, and report CAGR, "
21+
"total return, final value, drawdown, and Sharpe ratio."
22+
)
1923

2024

2125
async def build() -> tuple[QuantInvestWorkflow, object]:

agent_framework/models.py

Lines changed: 2 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,6 @@
1-
"""Data contracts and strategy catalog for the Agent Framework implementation."""
1+
"""Data contracts for the Agent Framework research tools."""
22

3-
from pathlib import Path
4-
from typing import Literal
5-
6-
from pydantic import BaseModel, Field, field_validator
7-
8-
9-
class StrategyIdea(BaseModel):
10-
name: str
11-
indicator: Literal["macd_rsi", "moving_average", "trix_uo"]
12-
description: str
13-
rationale: str
14-
investing_conditions: str
15-
expected_outcome: str
16-
17-
18-
class WorkflowRequest(BaseModel):
19-
ticker: str = Field(min_length=1, max_length=12)
20-
start_date: str
21-
end_date: str
22-
initial_capital: float = Field(default=10_000, gt=0)
23-
strategies: list[StrategyIdea] | None = None
24-
25-
@field_validator("ticker")
26-
@classmethod
27-
def normalize_ticker(cls, value: str) -> str:
28-
return value.upper().strip()
3+
from pydantic import BaseModel
294

305

316
class BacktestMetrics(BaseModel):
@@ -34,48 +9,3 @@ class BacktestMetrics(BaseModel):
349
maximum_drawdown: float
3510
sharpe_ratio: float
3611
final_value: float
37-
38-
39-
class StrategyRun(BaseModel):
40-
strategy: StrategyIdea
41-
metrics: BacktestMetrics
42-
output_directory: Path
43-
stock_data_file: Path
44-
signals_file: Path
45-
results_file: Path
46-
metrics_file: Path
47-
plot_file: Path
48-
49-
50-
class WorkflowResult(BaseModel):
51-
ticker: str
52-
strategy_ideas_file: Path
53-
runs: list[StrategyRun]
54-
55-
56-
IDEAS = (
57-
StrategyIdea(
58-
name="MACD RSI momentum",
59-
indicator="macd_rsi",
60-
description="MACD crossover confirmation with RSI filtering.",
61-
rationale="Pairs trend momentum with an overbought guardrail.",
62-
investing_conditions="Enter on a bullish crossover below RSI 70; exit on a bearish crossover or RSI above 75.",
63-
expected_outcome="Research hypothesis for sustained momentum.",
64-
),
65-
StrategyIdea(
66-
name="Moving-average trend",
67-
indicator="moving_average",
68-
description="20-day and 60-day moving-average crossover.",
69-
rationale="Transparent trend-following baseline.",
70-
investing_conditions="Enter and exit on the corresponding crossover.",
71-
expected_outcome="Research benchmark for persistent trends.",
72-
),
73-
StrategyIdea(
74-
name="TRIX ultimate-oscillator reversal",
75-
indicator="trix_uo",
76-
description="TRIX momentum with the Ultimate Oscillator.",
77-
rationale="Tests reversal timing across lookback periods.",
78-
investing_conditions="Enter on positive TRIX with UO below 50; exit on negative TRIX or UO above 70.",
79-
expected_outcome="Research hypothesis for momentum transitions.",
80-
),
81-
)

0 commit comments

Comments
 (0)