AutoGen AI Multi-Agents For Momentum Strategy Analysis
AutoGen AI Multi-Agents For Momentum Strategy Analysis
1
• Comparer Agent: Compares results for different moving average pairs.
• Group Chat Manager: Oversees agent interactions and manages the workflow to complete
the task.
� This content is intended for educational purposes only and is not an investment
recommendation. �
Hanane DUPOUY
[46]: #Conversable Agent
import PIL.Image
# #local image
image_path='./code/AutoGen_Conversable_agent.png'
img = PIL.Image.open(image_path)
img
# source: https://arxiv.org/pdf/2308.08155
# ==> AutoGen: Enabling Next-Gen LLM
# Applications via Multi-Agent Conversation
[46]:
[9]: import os
from autogen import AssistantAgent, UserProxyAgent, ConversableAgent,␣
↪GroupChat, GroupChatManager
3 Agents
3.1 AssistantAgent & UserProxyAgent
We will create AssistantAgent and UserProxyAgent:
• What is the difference between both agents?:
2
AssistantAgent: * It is behaving like an AI Assistant by using an LLM under the hood.
• It is not requiring human input or code execution.
• It is the standard form of an AI assistant: You give it an instruction like summarize a given
text or write a Python code, or refine and correct a given Python code.
• The behavior is instructed by the system message.
UserProxyAgent: It’s more sophisticated agent. It can: * Interact with human input * Execute
Code * Call functions or tools * You can either enable or disable the use of an LLM. If disabled
the Agent will execute code. If enabled and no code to execute, it will generate answers using the
LLM.
� � These 2 agents are sublcasses of a more generic class called ConversableAgent, which is the
highest-level agent abstraction.
This generic class allows agents to converse with each other through the exchange of the messages
while retaining the possibility of human intervention (if asked) to finish the required task. You can
create an agent, with only these 2 agents. However, to render the chat more dynamic and allow for
other agents to interven such as the CRITIC agent, I’ll also use GroupChatManager.
3.2 GroupChatManager
GroupChatManager Agent allows a dynamic group chat
[45]: import PIL.Image
# #local image
image_path='./code/autogen_dynamic_group_chat.png'
img = PIL.Image.open(image_path)
img
# source: https://arxiv.org/pdf/2308.08155
# ==> AutoGen: Enabling Next-Gen LLM
# Applications via Multi-Agent Conversation
[45]:
3
GroupChatManager
The Manager agent, which is an instance of the GroupChatManager class, serves as the conductor
of conversation among agents and repeats the following three steps:
1. Dynamically Selecting a single speaker (Code_generator for example),
2. Asking the speaker to respond, and collecting responses from this selected speaker, and
3. Broadcasting the selected speaker’s message to all other agents
[44]: import PIL.Image
# #local image
image_path='./code/AutoGen_GroupChatManager.png'
img = PIL.Image.open(image_path)
img
# source: https://arxiv.org/pdf/2308.08155
# ==> AutoGen: Enabling Next-Gen LLM
# Applications via Multi-Agent Conversation
[44]:
4
work_dir="code",
)
5
"executor": code_executor
},
llm_config=False,
human_input_mode="NEVER"
)
You are highly qualified in evaluating the quality of the code to implement␣
↪trading strategies, calculation buy and sell signal and computing the final␣
↪implemented?
You must provide a score for each of these aspects: Code Execubality,␣
↪Calculation, Buy and Sell Signals, Return.
""",
llm_config={
"config_list": config_list
}
)
6
5- Plot this trading strategy and save it in a file called␣
↪'nvidia_trading_strategy.png'
6- Calculate buy and sell signals. Plot them and save it in a file called␣
↪'buy_sell_signals.png'
7- Compute the final return of the strategy. Plot it and save it in a file␣
↪called 'final_return.png'
""",
)
--------------------------------------------------------------------------------
Let's implement and execute each step clearly. We will start by writing the
Python code for a simple momentum trading strategy, save it to a file, and work
through testing it with NVIDIA's historical prices. Here's the plan:
```python
# filename: momentum_trading_strategy.py
import pandas as pd
import numpy as np
7
import matplotlib.pyplot as plt
from pandas_datareader import data as web
signals['signal'] = 0.0
signals['signal'][short_window:] =
np.where(signals['short_mavg'][short_window:] >
signals['long_mavg'][short_window:], 1.0, 0.0)
signals['positions'] = signals['signal'].diff()
return signals
def main():
start_date = '2023-01-01'
end_date = '2023-10-31'
8
symbol = 'NVDA'
if __name__ == '__main__':
main()
```
Let’s proceed with Step 1-6, save the script, and execute it before proceeding
to Step 7.
--------------------------------------------------------------------------------
9
exitcode: 1 (execution failed)
Code output: Traceback (most recent call last):
File "/content/code/momentum_trading_strategy.py", line 64, in <module>
main()
File "/content/code/momentum_trading_strategy.py", line 52, in main
df = download_data(symbol, start_date, end_date)
File "/content/code/momentum_trading_strategy.py", line 10, in download_data
df = web.DataReader(symbol, 'yahoo', start, end)
File "/usr/local/lib/python3.10/dist-packages/pandas/util/_decorators.py",
line 213, in wrapper
return func(*args, **kwargs)
File "/usr/local/lib/python3.10/dist-packages/pandas_datareader/data.py", line
379, in DataReader
).read()
File "/usr/local/lib/python3.10/dist-packages/pandas_datareader/base.py", line
253, in read
df = self._read_one_data(self.url, params=self._get_params(self.symbols))
File "/usr/local/lib/python3.10/dist-
packages/pandas_datareader/yahoo/daily.py", line 149, in _read_one_data
resp = self._get_response(url, params=params, headers=self.headers)
File "/usr/local/lib/python3.10/dist-packages/pandas_datareader/base.py", line
181, in _get_response
raise RemoteDataError(msg)
pandas_datareader._utils.RemoteDataError: Unable to read URL: https://finance.ya
hoo.com/quote/NVDA/history?period1=1672545600&period2=1698811199&interval=1d&fre
quency=1d&filter=history
Response Text:
b'<html><meta
charset=\'utf-8\'><script>if(window!=window.top){document.write(\'<p>Content is
currently unavailable.</p><img src="//geo.yahoo.com/p?s=1197757039&t=\'+new Date
().getTime()+\'&_R=\'+encodeURIComponent(document.referrer)+\'&err=404&err_url=\
'+\'https%3A%2F%2Ffanyv88.com%3A443%2Fhttps%2Fbrb.yahoo.net%3A443%2Ffinance.yahoo.com%2Fdesktop%2Fquote%2FNV
DA%2Fhistory%2Findex.html\'+\'" width="0px" height="0px"/>\');}else{window.locat
ion.replace(\'https://www.yahoo.com/?err=404&err_url=https%3A%2F%2Ffanyv88.com%3A443%2Fhttps%2Fbrb.yahoo.net
%3A443%2Ffinance.yahoo.com%2Fdesktop%2Fquote%2FNVDA%2Fhistory%2Findex.html\');}<
/script><noscript><META http-equiv="refresh" content="0;URL=\'https://www.yahoo.
com/?err=404&err_url=https%3A%2F%2Ffanyv88.com%3A443%2Fhttps%2Fbrb.yahoo.net%3A443%2Ffinance.yahoo.com%2Fdes
ktop%2Fquote%2FNVDA%2Fhistory%2Findex.html\'"></noscript></html>'
--------------------------------------------------------------------------------
10
Finance directly for historical data. This is a common issue as Yahoo Finance's
API changes over time. As an alternative, we can use the `yfinance` library,
which is more reliable for downloading stock data from Yahoo Finance.
```python
# filename: momentum_trading_strategy.py
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import yfinance as yf
signals['signal'] = 0.0
signals['signal'][short_window:] =
np.where(signals['short_mavg'][short_window:] >
signals['long_mavg'][short_window:], 1.0, 0.0)
signals['positions'] = signals['signal'].diff()
return signals
11
'^', markersize=10, color='g', label='Buy Signal')
plt.plot(signals.loc[signals.positions == -1.0].index,
signals.short_mavg[signals.positions == -1.0],
'v', markersize=10, color='r', label='Sell Signal')
plt.title('NVIDIA Trading Strategy')
plt.legend()
plt.savefig(filename)
def main():
start_date = '2023-01-01'
end_date = '2023-10-31'
symbol = 'NVDA'
if __name__ == '__main__':
main()
```
Please ensure you have the `yfinance` library installed. If not, you can install
it using:
```sh
pip install yfinance
```
Now, run the above Python script again. Once it's successfully run, I'll guide
you on the next step to compute and plot the final return.
--------------------------------------------------------------------------------
12
Code output:
[*********************100%***********************] 1 of 1 completed
/content/code/momentum_trading_strategy.py:21: FutureWarning:
ChainedAssignmentError: behaviour will change in pandas 3.0!
You are setting values through chained assignment. Currently this works in
certain cases, but when using Copy-on-Write (which will become the default
behaviour in pandas 3.0) this will never work to update the original DataFrame
or Series, because the intermediate object on which we are setting values will
behave as a copy.
A typical example is when you are setting values in a column of a DataFrame,
like:
df["col"][row_indexer] = value
signals['signal'][short_window:] =
np.where(signals['short_mavg'][short_window:] >
signals['long_mavg'][short_window:], 1.0, 0.0)
--------------------------------------------------------------------------------
The script executed successfully and generated the required CSV and PNG files.
However, we encountered a `FutureWarning` regarding the chained assignment
operation in Pandas, which may cause issues in the future when Pandas updates
its default behavior. We can resolve this by using the `loc` indexer to assign
values without triggering the warning.
```python
# Modify the assignment line in the momentum_trading_strategy function to use
loc
signals.loc[signals.index[short_window:], 'signal'] = np.where(
signals['short_mavg'][short_window:] > signals['long_mavg'][short_window:],
1.0, 0.0
)
```
13
### Step 7: Compute and Plot Final Return
To calculate and plot the final return of the strategy, we should add a section
to compute and plot these results. Let's extend our script with these
functionalities:
```python
def compute_final_return(signals, filename='final_return.png'):
"""Compute and plot the final cumulative return of the trading strategy"""
signals['strategy_returns'] = signals['positions'].shift(1) *
(signals['price'].pct_change())
signals['cumulative_strategy_return'] = (signals['strategy_returns'] +
1).cumprod()
plt.figure(figsize=(12, 8))
plt.plot(signals['cumulative_strategy_return'], label='Cumulative Strategy
Return')
plt.title('Final Return of the Trading Strategy')
plt.legend()
plt.savefig(filename)
def main():
start_date = '2023-01-01'
end_date = '2023-10-31'
symbol = 'NVDA'
if __name__ == '__main__':
main()
```
After adding this function, execute your script once more to compute and plot
the final return of your trading strategy. This will generate and save a plot of
the cumulative strategy return, showing you the final return of the momentum
14
trading strategy over the specified period.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
```python
# filename: momentum_trading_strategy.py
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import yfinance as yf
15
signals['short_mavg'] = df['Close'].rolling(window=short_window,
min_periods=1).mean()
signals['long_mavg'] = df['Close'].rolling(window=long_window,
min_periods=1).mean()
signals['positions'] = signals['signal'].diff()
return signals
plt.figure(figsize=(12, 8))
plt.plot(signals['cumulative_strategy_return'], label='Cumulative Strategy
Return')
plt.title('Final Return of the Trading Strategy')
plt.legend()
plt.savefig(filename)
16
def main():
start_date = '2023-01-01'
end_date = '2023-10-31'
symbol = 'NVDA'
if __name__ == '__main__':
main()
```
After updating the file, please run the script again. This will handle the
computation and plotting of the final return, resolving any previously
encountered warnings.
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
The script has executed successfully, generating the outputs as expected. Here's
17
a breakdown of the evaluation for each aspect of the code:
### Calculation
- **Score: 4.5/5**
- The momentum trading strategy using moving average crossovers (short and
long windows) was implemented correctly.
- A minor warning was handled appropriately, ensuring future compatibility.
### Return
- **Score: 5/5**
- Strategy returns were correctly calculated through percent change in price
and strategy positions.
- The cumulative return was plotted and saved, providing visibility into the
strategy's performance over the specified period.
Overall, the code meets standard requirements for implementing and testing a
momentum trading strategy on historical stock data. The handling of data
downloads, signal calculations, and visual outputs were effectively executed.
--------------------------------------------------------------------------------
Remember, tweaking the short-term and long-term windows and observing different
stocks may give you varied results and insights based on the momentum strategy
you implemented.
TERMINATE
18
--------------------------------------------------------------------------------
TERMINATE
--------------------------------------------------------------------------------
4.4 Takeaways:
Agents Workflow
Even between the code generator and the code executor, there’s a reflective process: when the code
from the generator isn’t executable, the generator adjusts its initial implementation based on the
executor’s feedback.
--------------------------
**Next speaker: Code_executor**
--------------------------
**Next speaker: Code_generator**
The script executed successfully and generated the required CSV and PNG files. However, we enco
“Functional Feedback”:
As I didn’t specify the date of today, the agent fetch historical prices based on its cutoff knowledge
and give me 2023 prices.
19
4.5 Plots
[9]: import PIL.Image
# #local image
image_path='./code/nvidia_trading_strategy.png'
img = PIL.Image.open(image_path)
img
[9]:
20
5.2 Multi-agent collaboration
[16]: # config_list = [{"model": "gpt-4o", "api_key": OPENAI_API_KEY}]
code_executor = LocalCommandLineCodeExecutor(
timeout=60,
work_dir="code",
)
You are highly qualified in evaluating the quality of the code to implement␣
↪trading strategies, calculation buy and sell signal and computing the final␣
↪implemented?
You must provide a score for each of these aspects: Code Execubality,␣
↪Calculation, Buy and Sell Signals, Return.
21
""",
llm_config={
"config_list": config_list
},
human_input_mode="NEVER"
)
""",
llm_config={
"config_list": config_list
},
human_input_mode="NEVER"
)
5- For each pair of moving averages, save the results in a csv file called␣
↪'nvidia_trading_strategy_{pair_of_moving_average}.csv'
6- For each pair of moving averages, plot this trading strategy and save it␣
↪in a file called 'nvidia_trading_strategy_{pair_of_moving_average}.png'
7- For each pair of moving averages, calculate buy and sell signals. Plot␣
↪them and save it in a file called 'buy_sell_signals_{pair_of_moving_average}.
↪png'
8- For each pair of moving averages, compute the final return of the␣
↪strategy, and provide these results in a markdown format.
""",
)
22
Let's proceed step by step:
1- Which date is today?
2- Propose a Python code implementation of a momentum trading strategy with
2 moving averages: short and long.
3- Save in a file called 'momentum_trading_strategy.py'
4- Apply this code to NVIDIA historical price of the current year, with 4
different pair of moving averages.
5- For each pair of moving averages, save the results in a csv file called
'nvidia_trading_strategy_{pair_of_moving_average}.csv'
6- For each pair of moving averages, plot this trading strategy and save it
in a file called 'nvidia_trading_strategy_{pair_of_moving_average}.png'
7- For each pair of moving averages, calculate buy and sell signals. Plot
them and save it in a file called
'buy_sell_signals_{pair_of_moving_average}.png'
8- For each pair of moving averages, compute the final return of the
strategy, and provide these results in a markdown format.
--------------------------------------------------------------------------------
```python
from datetime import date
today = date.today()
print("Today's date is:", today)
```
Please execute the above code and provide the date. This helps to ensure that we
use the correct historical data for NVIDIA from the current year for the
subsequent steps. Once you provide the date, we'll proceed to the next steps.
--------------------------------------------------------------------------------
23
exitcode: 0 (execution succeeded)
Code output: Today's date is: 2024-11-10
--------------------------------------------------------------------------------
Now, we'll create a Python code implementation for a momentum trading strategy
using two moving averages: short and long.
```python
# filename: momentum_trading_strategy.py
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
signals['signal'] = 0.0
signals['signal'][short_window:] =
np.where(signals['short_mavg'][short_window:] >
signals['long_mavg'][short_window:], 1.0, 0.0)
signals['positions'] = signals['signal'].diff()
return signals
```
Now that we have implemented the momentum trading strategy, let's download
NVIDIA's historical data for the current year and apply different moving
averages in the next steps. We'll also adapt the code to save results and plots
for each pair.
24
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
### Step 3: Applying the Code to NVIDIA Historical Prices for 2024
```python
# filename: apply_momentum_trading.py
import yfinance as yf
import pandas as pd
import matplotlib.pyplot as plt
from momentum_trading_strategy import momentum_trading_strategy
25
# Apply and process each moving average pair
for short_window, long_window in ma_pairs:
# Apply the trading strategy
signals = momentum_trading_strategy(nvidia, short_window, long_window)
plt.figure(figsize=(10, 5))
plt.plot(signals['price'], label='Price')
plt.scatter(buy_signals.index, buy_signals['price'], marker='^', color='g',
label='Buy Signal')
plt.scatter(sell_signals.index, sell_signals['price'], marker='v',
color='r', label='Sell Signal')
plt.legend()
plt.title(f'Buy and Sell Signals with MA {short_window} and {long_window}')
plt.savefig(f'buy_sell_signals_{short_window}_{long_window}.png')
plt.close()
26
--------------------------------------------------------------------------------
df["col"][row_indexer] = value
signals['signal'][short_window:] =
np.where(signals['short_mavg'][short_window:] >
signals['long_mavg'][short_window:], 1.0, 0.0)
/content/code/apply_momentum_trading.py:49: FutureWarning: Series.__getitem__
treating keys as positions is deprecated. In a future version, integer keys will
always be treated as labels (consistent with DataFrame behavior). To access a
value by position, use `ser.iloc[pos]`
cumulative_return = (1 + strategy_returns).cumprod()[-1] - 1
/content/code/momentum_trading_strategy.py:17: FutureWarning:
ChainedAssignmentError: behaviour will change in pandas 3.0!
You are setting values through chained assignment. Currently this works in
certain cases, but when using Copy-on-Write (which will become the default
behaviour in pandas 3.0) this will never work to update the original DataFrame
or Series, because the intermediate object on which we are setting values will
behave as a copy.
A typical example is when you are setting values in a column of a DataFrame,
like:
df["col"][row_indexer] = value
27
Use `df.loc[row_indexer, "col"] = values` instead, to perform the assignment in
a single step and ensure this keeps updating the original `df`.
signals['signal'][short_window:] =
np.where(signals['short_mavg'][short_window:] >
signals['long_mavg'][short_window:], 1.0, 0.0)
/content/code/apply_momentum_trading.py:49: FutureWarning: Series.__getitem__
treating keys as positions is deprecated. In a future version, integer keys will
always be treated as labels (consistent with DataFrame behavior). To access a
value by position, use `ser.iloc[pos]`
cumulative_return = (1 + strategy_returns).cumprod()[-1] - 1
/content/code/momentum_trading_strategy.py:17: FutureWarning:
ChainedAssignmentError: behaviour will change in pandas 3.0!
You are setting values through chained assignment. Currently this works in
certain cases, but when using Copy-on-Write (which will become the default
behaviour in pandas 3.0) this will never work to update the original DataFrame
or Series, because the intermediate object on which we are setting values will
behave as a copy.
A typical example is when you are setting values in a column of a DataFrame,
like:
df["col"][row_indexer] = value
signals['signal'][short_window:] =
np.where(signals['short_mavg'][short_window:] >
signals['long_mavg'][short_window:], 1.0, 0.0)
/content/code/apply_momentum_trading.py:49: FutureWarning: Series.__getitem__
treating keys as positions is deprecated. In a future version, integer keys will
always be treated as labels (consistent with DataFrame behavior). To access a
value by position, use `ser.iloc[pos]`
cumulative_return = (1 + strategy_returns).cumprod()[-1] - 1
/content/code/momentum_trading_strategy.py:17: FutureWarning:
ChainedAssignmentError: behaviour will change in pandas 3.0!
You are setting values through chained assignment. Currently this works in
certain cases, but when using Copy-on-Write (which will become the default
behaviour in pandas 3.0) this will never work to update the original DataFrame
or Series, because the intermediate object on which we are setting values will
behave as a copy.
28
A typical example is when you are setting values in a column of a DataFrame,
like:
df["col"][row_indexer] = value
signals['signal'][short_window:] =
np.where(signals['short_mavg'][short_window:] >
signals['long_mavg'][short_window:], 1.0, 0.0)
/content/code/apply_momentum_trading.py:49: FutureWarning: Series.__getitem__
treating keys as positions is deprecated. In a future version, integer keys will
always be treated as labels (consistent with DataFrame behavior). To access a
value by position, use `ser.iloc[pos]`
cumulative_return = (1 + strategy_returns).cumprod()[-1] - 1
Final return for MA pair (5, 20): 84.48%
Final return for MA pair (10, 50): 5.04%
Final return for MA pair (20, 100): 40.62%
Final return for MA pair (50, 200): 8.78%
--------------------------------------------------------------------------------
#### Evaluation of the Code Implementation for the Momentum Trading Strategy
1. **Code Executability:**
- **Score**: 9/10
- The code executes successfully and fetches NVIDIA stock data for 2024
using `yfinance`.
- Libraries such as `pandas`, `numpy`, `matplotlib`, and `yfinance` are
readily available and used appropriately.
- Future warnings related to `pandas` were raised. These do not prevent
execution currently but may in future versions.
2. **Calculation:**
- **Score**: 8/10
- The moving averages (short and long) are calculated correctly using a
rolling mean.
- The strategy's conditions for generating signals based on moving average
crossover are implemented, although chained assignment warnings suggest
29
improvements for future compatibility.
- Cumulative return calculation needs adjustment for cleaner handling.
4. **Return:**
- **Score**: 9/10
- The strategy's final returns are calculated correctly as displayed from
strategy execution.
- Future warnings on series accessing are to be considered for future
adaptability.
Markdown format of the returns for each moving average pair from the execution:
```markdown
## Momentum Trading Strategy Results for NVIDIA 2024
### Recommendations:
- To address future compatibility, consider revising the code to adapt to the
new pandas `Copy-on-Write` behavior.
- Use explicit index locating, `iloc` for position-based indexing, to suppress
the warnings and ensure clarity and longer-term usability.
- These minor tweaks will enhance precision and compatibility after pandas 3.0.
--------------------------------------------------------------------------------
30
Next speaker: Comparer
#### Detailed Commentary on Buy and Sell Signals & Final Returns
### Conclusion
The strategy highlights vary in performance, with shorter periods reacting
quicker to price changes and longer pairs yielding stable but slower signals.
Each pair contains unique thresholds of noise vs. trend capturing, allowing
investors to tailor their strategies according to risk preferences and market
expectations.
31
### Implementation Considerations
To adhere to future standards:
- Consider refactoring assignment methods to resolve pandas' `Copy-on-Write`
warnings, enhancing stability.
- Implement positional indexing with `.iloc` to avoid deprecation conflicts,
ensuring enduring script functionality.
--------------------------------------------------------------------------------
TERMINATE
--------------------------------------------------------------------------------
The multi-agent framework tries various pair of short/long window for moving average, and com-
puted their returns:
32
� This content is intended for educational purposes only and is not an investment
recommendation. �
5.3 Plots
[18]: import PIL.Image
# #local image
ma_pairs = [(5, 20), (10, 50), (20, 100), (50, 200)]
for pair in ma_pairs:
image_path=f'./code/nvidia_trading_strategy_{pair[0]}_{pair[1]}.png'
img = PIL.Image.open(image_path)
display(img)
33
[19]: import PIL.Image
# #local image
ma_pairs = [(5, 20), (10, 50), (20, 100), (50, 200)]
for pair in ma_pairs:
image_path=f'./code/buy_sell_signals_{pair[0]}_{pair[1]}.png'
img = PIL.Image.open(image_path)
display(img)
34
35
[21]: import pandas as pd
36
213 2024-11-05 00:00:00+00:00 139.910004 136.691998 137.831000 0.0
214 2024-11-06 00:00:00+00:00 145.610001 137.945999 138.479000 0.0
215 2024-11-07 00:00:00+00:00 148.880005 141.170001 139.182500 1.0
216 2024-11-08 00:00:00+00:00 147.630005 143.616003 139.824001 1.0
positions
212 -1.0
213 0.0
214 0.0
215 1.0
216 0.0
[42]: df_5_20.tail(10)
positions
207 0.0
208 0.0
209 0.0
210 0.0
211 0.0
212 -1.0
213 0.0
214 0.0
215 1.0
216 0.0
[40]: df_50_200.tail()
37
positions
212 0.0
213 0.0
214 0.0
215 0.0
216 0.0
[ ]: df_50_200.tail(50)
6 Final Takeways:
• Easy to implement.
• The Critic Agent functions effectively, reflecting on and improving the code with useful rec-
ommendations.
• The workflow is smooth and transparent, with clear visibility of each agent’s role at every
stage.
38