Reflection Agent Using LangChain For Trading Strategy
Reflection Agent Using LangChain For Trading Strategy
Mounted at /content/drive
2 Steps
Here are the different steps of a basic Reflection:
Generator: 1. The Generator LLM answers to a given query. *Prompt_generator* = Propose
a Python code implemtation for a trading strategy
1
Reflection 2. The Reflection LLM will evaluate the ouput of the Generator.*Prompt_reflector*
= Evalute the Python code implementation generated by the Generator.
Review 3. With the first implementation and the reflection (feedback), LLM (generator) will make
the correction for the Python code implementation. You have below one call example and A loop
example.
[1]: !pip install -U --quiet langchain langgraph
!pip install --quiet langchain_openai
���������������������������������������� 817.7/817.7
kB 7.7 MB/s eta 0:00:00
���������������������������������������� 59.3/59.3 kB
6.3 MB/s eta 0:00:00
���������������������������������������� 1.9/1.9 MB
12.9 MB/s eta 0:00:00
���������������������������������������� 291.3/291.3
kB 12.8 MB/s eta 0:00:00
���������������������������������������� 115.2/115.2
kB 11.0 MB/s eta 0:00:00
���������������������������������������� 49.4/49.4 kB
4.8 MB/s eta 0:00:00
���������������������������������������� 53.0/53.0 kB
4.6 MB/s eta 0:00:00
���������������������������������������� 141.1/141.1
kB 13.8 MB/s eta 0:00:00
���������������������������������������� 311.2/311.2
kB 9.7 MB/s eta 0:00:00
���������������������������������������� 1.8/1.8 MB
46.8 MB/s eta 0:00:00
���������������������������������������� 75.6/75.6 kB
6.7 MB/s eta 0:00:00
���������������������������������������� 77.9/77.9 kB
7.6 MB/s eta 0:00:00
���������������������������������������� 58.3/58.3 kB
5.8 MB/s eta 0:00:00
2
llm = ChatOpenAI(model="gpt-3.5-turbo-0125", temperature=0,␣
↪api_key=OPENAI_API_KEY)
3 Initial Generate
3.0.1 Prompt generate
↪Your responses should strictly consist of executable Python code tailored to␣
- Augment your code by inline comments and docstrings, when it's necessary, to␣
↪clarify the functionality and the structure of the code.
- Make sure all code conforms to Python best practices and conventions.
- This code will be used as it is by the user, so make sure to generate an␣
↪executable code in prodution environment.
- Only produce executable Python code. Omit any explanatory text, descriptions,␣
↪or elements that are not code from your responses.
Answer only with Pyton code without any explanatory text, descriptions, or␣
↪elements that are not code from your responses.
"""
3.0.2 Generator
[5]: prompt = ChatPromptTemplate.from_messages(
[
(
"system",
prompt_generate,
),
MessagesPlaceholder(variable_name="messages"),
]
)
3
3.0.3 Run Generator on a query [request]
I choose here the RSI (which is a little bit challenging for a Python code generaion)
request = HumanMessage(
content = query
)
code = ""
for chunk in generate.stream({"messages": [request]}):
print(chunk.content, end="")
code += chunk.content
```python
def calculate_rsi(prices, n=14):
"""
Calculate the Relative Strength Index (RSI) of a given price series.
Parameters:
prices (list): List of prices.
n (int): Number of periods to consider for RSI calculation.
Returns:
float: RSI value.
"""
deltas = [prices[i + 1] - prices[i] for i in range(len(prices) - 1)]
gain = [d if d > 0 else 0 for d in deltas]
loss = [-d if d < 0 else 0 for d in deltas]
avg_gain = sum(gain[:n]) / n
avg_loss = sum(loss[:n]) / n
rs = avg_gain / avg_loss
rsi = 100 - (100 / (1 + rs))
return rsi
```
4
4 Reflection
4.0.1 Prompt reflection
[9]: prompt_reflection = """You are tasked with evaluating Python code for␣
↪algorithmic trading. Here are your responsibilities:
- Assess the code's readability, check for bugs, and ensure there's adequate␣
↪documentation. Provide specific feedback on areas needing correction or␣
↪simplification.
- Ensure the code is well-structured into modules and functions, with each␣
↪performing a single responsibility. Functions and classes should be concise␣
↪modification.
- Review the implemented logic to confirm there are no algorithmic errors. Pay␣
↪close attention to typical issues such as off-by-one errors or incorrect␣
↪condition checks.
- Verify that all functions, classes, and modules have comprehensive docstrings␣
↪explaining their purpose, parameters, and returns. Only provide feedback if␣
- If no suggestions are necessary, respond with only the relevant Python code,␣
↪omitting any explanatory text or descriptions.
"""
5
4.0.3 Run reflect LLM on [request, previously generated code]
print(chunk.content, end="")
reflection += chunk.content
- The calculation of RSI seems to have a bug in the loop where it updates
`avg_gain` and `avg_loss`. The loop should iterate until `len(prices)` instead
of `len(prices) - 1`.
- The loop should start from `n` instead of `n` to consider the correct range
for updating `avg_gain` and `avg_loss`.
- The calculation of `rs` and `rsi` should be done after the loop to ensure the
correct values are used.
- The function lacks input validation to handle cases where the length of
`prices` is less than `n+1`.
- The function could benefit from more descriptive variable names for better
readability.
```python
def calculate_rsi(prices, n=14):
"""
Calculate the Relative Strength Index (RSI) of a given price series.
Parameters:
prices (list): List of prices.
n (int): Number of periods to consider for RSI calculation.
Returns:
float: RSI value.
"""
if len(prices) < n + 1:
raise ValueError("Number of prices should be greater than n+1 for RSI
calculation.")
avg_gain = sum(gain[:n]) / n
avg_loss = sum(loss[:n]) / n
6
rs = avg_gain / avg_loss
rsi = 100 - (100 / (1 + rs))
return rsi
```
5 Review
Based on the first code implementation proposition from the Generetaor + the
feedback from the reflection: Generate a new python code implementation
One call
[21]: review = ""
for chunk in generate.stream(
{"messages": [request, AIMessage(content=code),␣
↪HumanMessage(content=reflection)]}
):
print(chunk.content, end="")
review +=chunk.content
```python
def calculate_rsi(prices, n=14):
"""
Calculate the Relative Strength Index (RSI) of a given price series.
Parameters:
prices (list): List of prices.
n (int): Number of periods to consider for RSI calculation.
Returns:
float: RSI value.
"""
if len(prices) < n + 1:
raise ValueError("Number of prices should be greater than n+1 for RSI
calculation.")
avg_gain = sum(gain[:n]) / n
avg_loss = sum(loss[:n]) / n
7
for i in range(n, len(prices)):
avg_gain = (avg_gain * (n - 1) + gain[i]) / n
avg_loss = (avg_loss * (n - 1) + loss[i]) / n
rs = avg_gain / avg_loss
rsi = 100 - (100 / (1 + rs))
return rsi
```
# ):
# print(chunk.content, end="")
# END +=chunk.content
Loop
[23]: #3 iterations
for i in range(0,3):
print("Generator with feedback from Reflection")
corrector = ""
for chunk in generate.stream(
{"messages": [request, AIMessage(content=reflection),␣
↪HumanMessage(content=review)]}
):
print(chunk.content, end="")
corrector +=chunk.content
review = corrector
print("\n")
print("*"*50)
print("\nReflection")
reflection = ""
for chunk in reflect.stream({"messages": [request,␣
↪HumanMessage(content=corrector)]}):
print(chunk.content, end="")
reflection += chunk.content
print("*"*50)
8
should work effectively for computing the RSI value based on the given price
series and the specified number of periods.
If you have any specific questions or need further assistance with this code,
feel free to ask!
**************************************************
Reflection
```python
def calculate_rsi(prices, n=14):
"""
Calculate the Relative Strength Index (RSI) for a given price series.
Args:
prices (list): List of prices.
n (int): Number of periods for RSI calculation (default is 14).
Returns:
float: The RSI value.
"""
if len(prices) < 2:
raise ValueError("Input prices list must have at least 2 elements")
avg_gain = sum(gains[:n]) / n
avg_loss = sum(losses[:n]) / n
return rsi
```**************************************************
Generator with feedback from Reflection
I'm glad you found the code implementation satisfactory. If you have any more
requests or need further assistance with Python code for algorithmic trading
strategies, feel free to ask!
**************************************************
Reflection
```python
def calculate_rsi(data, window=14):
"""
Calculate the Relative Strength Index (RSI) for a given data set.
9
Parameters:
data (list): List of closing prices.
window (int): Window size for RSI calculation (default is 14).
Returns:
list: List of RSI values.
"""
delta = [data[i + 1] - data[i] for i in range(len(data) - 1)]
gain = [d if d > 0 else 0 for d in delta]
loss = [abs(d) if d < 0 else 0 for d in delta]
return rsi
```**************************************************
Generator with feedback from Reflection
I'm here to help! Just let me know what you need, and I'll provide you with the
Python code you require for your algorithmic trading strategies.
**************************************************
Reflection
```python
def calculate_rsi(prices, n=14):
"""
Calculate the Relative Strength Index (RSI) for a given list of prices.
10
rsi[:n] = 100. - 100. / (1. + rs)
if delta > 0:
upval = delta
downval = 0.
else:
upval = 0.
downval = -delta
up = (up * (n - 1) + upval) / n
down = (down * (n - 1) + downval) / n
rs = up / down
rsi[i] = 100. - 100. / (1. + rs)
return rsi
```**************************************************
```python
def calculate_rsi(prices, n=14):
"""
Calculate the Relative Strength Index (RSI) for a given list of prices.
if delta > 0:
upval = delta
downval = 0.
11
else:
upval = 0.
downval = -delta
up = (up * (n - 1) + upval) / n
down = (down * (n - 1) + downval) / n
rs = up / down
rsi[i] = 100. - 100. / (1. + rs)
return rsi
```
↪Your responses should strictly consist of executable Python code tailored to␣
- Augment your code by inline comments and docstrings, when it's necessary, to␣
↪clarify the functionality and the structure of the code.
- Make sure all code conforms to Python best practices and conventions.
- This code will be used as it is by the user, so make sure to generate an␣
↪executable code in prodution environment.
- Only produce executable Python code. Omit any explanatory text, descriptions,␣
↪or elements that are not code from your responses.
Answer only with Pyton code without any explanatory text, descriptions, or␣
↪elements that are not code from your responses.
"""
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
prompt_generate,
12
),
MessagesPlaceholder(variable_name="messages"),
]
)
- Assess the code's readability, check for bugs, and ensure there's adequate␣
↪documentation. Provide specific feedback on areas needing correction or␣
↪simplification.
- Ensure the code is well-structured into modules and functions, with each␣
↪performing a single responsibility. Functions and classes should be concise␣
↪modification.
- Review the implemented logic to confirm there are no algorithmic errors. Pay␣
↪close attention to typical issues such as off-by-one errors or incorrect␣
↪condition checks.
- Verify that all functions, classes, and modules have comprehensive docstrings␣
↪explaining their purpose, parameters, and returns. Only provide feedback if␣
- If no suggestions are necessary, respond with only the relevant Python code,␣
↪omitting any explanatory text or descriptions.
"""
reflection_prompt = ChatPromptTemplate.from_messages(
[
(
"system",
prompt_reflection,
),
MessagesPlaceholder(variable_name="messages"),
13
]
)
request = HumanMessage(
content = query
)
code = ""
for chunk in generate.stream({"messages": [request]}):
print(chunk.content, end="")
code += chunk.content
#3 iterations
for i in range(0,3):
print("\nReflection")
reflection = ""
for chunk in reflect.stream({"messages": [request,␣
↪HumanMessage(content=code)]}):
print(chunk.content, end="")
reflection += chunk.content
print("\n")
print("*"*50)
print("Generator with feedback from Reflection")
corrector = ""
for chunk in generate.stream(
{"messages": [request, AIMessage(content=code),␣
↪HumanMessage(content=reflection)]}
):
print(chunk.content, end="")
corrector +=chunk.content
code = corrector
print("*"*50)
```python
def calculate_rsi(prices, n=14):
"""
14
Calculate the Relative Strength Index (RSI) for a given list of prices.
Parameters:
prices (list): List of prices.
n (int): Number of periods to consider for RSI calculation.
Returns:
float: The Relative Strength Index (RSI) value.
"""
deltas = [prices[i + 1] - prices[i] for i in range(len(prices) - 1)]
gain = [delta if delta > 0 else 0 for delta in deltas]
loss = [-delta if delta < 0 else 0 for delta in deltas]
avg_gain = sum(gain[:n]) / n
avg_loss = sum(loss[:n]) / n
rs = avg_gain / avg_loss
rsi = 100 - (100 / (1 + rs))
return rsi
```
Reflection
- The code implementation of RSI looks good in terms of logic and readability.
- It follows the PEP 8 guidelines.
- The function `calculate_rsi` is well-documented with clear explanations of
parameters and return value.
- The calculation of RSI seems correct based on the standard formula for
Relative Strength Index.
- One minor improvement could be to add a check for division by zero when
calculating `rs` to handle the case where `avg_loss` is zero.
```python
def calculate_rsi(prices, n=14):
"""
Calculate the Relative Strength Index (RSI) for a given list of prices.
Parameters:
prices (list): List of prices.
n (int): Number of periods to consider for RSI calculation.
Returns:
float: The Relative Strength Index (RSI) value.
15
"""
deltas = [prices[i + 1] - prices[i] for i in range(len(prices) - 1)]
gain = [delta if delta > 0 else 0 for delta in deltas]
loss = [-delta if delta < 0 else 0 for delta in deltas]
avg_gain = sum(gain[:n]) / n
avg_loss = sum(loss[:n]) / n
return rsi
```
**************************************************
Generator with feedback from Reflection
```python
def calculate_rsi(prices, n=14):
"""
Calculate the Relative Strength Index (RSI) for a given list of prices.
Parameters:
prices (list): List of prices.
n (int): Number of periods to consider for RSI calculation.
Returns:
float: The Relative Strength Index (RSI) value.
"""
deltas = [prices[i + 1] - prices[i] for i in range(len(prices) - 1)]
gain = [delta if delta > 0 else 0 for delta in deltas]
loss = [-delta if delta < 0 else 0 for delta in deltas]
avg_gain = sum(gain[:n]) / n
avg_loss = sum(loss[:n]) / n
return rsi
```**************************************************
16
Reflection
- The code implementation of RSI looks correct in terms of logic.
- It would be beneficial to add more comments to explain the calculations being
performed in the function.
- The function could be improved by breaking down the calculation into smaller,
more descriptive functions for better readability and maintainability.
- Consider adding input validation to ensure that the length of prices is
greater than the specified period 'n'.
- It's recommended to use more descriptive variable names for better
readability.
```python
def calculate_rsi(prices, n=14):
"""
Calculate the Relative Strength Index (RSI) for a given list of prices.
Parameters:
prices (list): List of prices.
n (int): Number of periods to consider for RSI calculation.
Returns:
float: The Relative Strength Index (RSI) value.
"""
def calculate_deltas(prices):
return [prices[i + 1] - prices[i] for i in range(len(prices) - 1)]
def calculate_gain_loss(deltas):
gain = [delta if delta > 0 else 0 for delta in deltas]
loss = [-delta if delta < 0 else 0 for delta in deltas]
return gain, loss
deltas = calculate_deltas(prices)
gain, loss = calculate_gain_loss(deltas)
avg_gain, avg_loss = calculate_avg_gain_loss(gain, loss, n)
17
return rsi
```
**************************************************
Generator with feedback from Reflection
```python
def calculate_rsi(prices, n=14):
"""
Calculate the Relative Strength Index (RSI) for a given list of prices.
Parameters:
prices (list): List of prices.
n (int): Number of periods to consider for RSI calculation.
Returns:
float: The Relative Strength Index (RSI) value.
"""
def calculate_deltas(prices):
return [prices[i + 1] - prices[i] for i in range(len(prices) - 1)]
def calculate_gain_loss(deltas):
gain = [delta if delta > 0 else 0 for delta in deltas]
loss = [-delta if delta < 0 else 0 for delta in deltas]
return gain, loss
if len(prices) <= n:
raise ValueError("Length of prices should be greater than the specified
period 'n'.")
deltas = calculate_deltas(prices)
gain, loss = calculate_gain_loss(deltas)
avg_gain, avg_loss = calculate_avg_gain_loss(gain, loss, n)
return rsi
```**************************************************
18
Reflection
The implementation of the RSI calculation function is well-structured and
follows PEP 8 guidelines. The code is clear and concise, with appropriate
documentation. However, there are a few suggestions for improvement:
1. **Efficiency**: The function recalculates the average gain and loss for each
period, which can be optimized by updating the averages incrementally. This can
improve the efficiency, especially for large datasets.
2. **Boundary Check**: The function should handle cases where the average loss
is zero to avoid division by zero error.
```python
def calculate_rsi(prices, n=14):
"""
Calculate the Relative Strength Index (RSI) for a given list of prices.
Parameters:
prices (list): List of prices.
n (int): Number of periods to consider for RSI calculation.
Returns:
float: The Relative Strength Index (RSI) value.
"""
def calculate_deltas(prices):
return [prices[i + 1] - prices[i] for i in range(len(prices) - 1)]
def calculate_gain_loss(deltas):
gain = [delta if delta > 0 else 0 for delta in deltas]
loss = [-delta if delta < 0 else 0 for delta in deltas]
return gain, loss
if len(prices) <= n:
raise ValueError("Length of prices should be greater than the specified
period 'n'.")
19
deltas = calculate_deltas(prices)
gain, loss = calculate_gain_loss(deltas)
avg_gain, avg_loss = calculate_avg_gain_loss(gain, loss, n)
if avg_loss == 0:
rs = float('inf')
else:
rs = avg_gain / avg_loss
return rsi
```
**************************************************
Generator with feedback from Reflection
```python
def calculate_rsi(prices, n=14):
"""
Calculate the Relative Strength Index (RSI) for a given list of prices.
Parameters:
prices (list): List of prices.
n (int): Number of periods to consider for RSI calculation.
Returns:
float: The Relative Strength Index (RSI) value.
"""
def calculate_deltas(prices):
return [prices[i + 1] - prices[i] for i in range(len(prices) - 1)]
def calculate_gain_loss(deltas):
gain = [delta if delta > 0 else 0 for delta in deltas]
loss = [-delta if delta < 0 else 0 for delta in deltas]
return gain, loss
if len(prices) <= n:
raise ValueError("Length of prices should be greater than the specified
period 'n'.")
20
deltas = calculate_deltas(prices)
gain, loss = calculate_gain_loss(deltas)
avg_gain, avg_loss = calculate_avg_gain_loss(gain, loss, n, sum(gain[:n]) /
n, sum(loss[:n]) / n)
if avg_loss == 0:
rs = float('inf')
else:
rs = avg_gain / avg_loss
return rsi
```**************************************************
request = HumanMessage(
content = query
)
#3 iterations
for i in range(0,3):
print("\n")
print("*"*50)
print("\nReflection")
reflection = ""
for chunk in reflect.stream({"messages": [request,␣
↪HumanMessage(content=code)]}):
print(chunk.content, end="")
reflection += chunk.content
print("\n")
print("*"*50)
21
print("\nGenerator with feedback from Reflection\n")
corrector = ""
for chunk in generate.stream(
{"messages": [request, AIMessage(content=code),␣
↪HumanMessage(content=reflection)]}
):
print(chunk.content, end="")
corrector +=chunk.content
code = corrector
print("\n")
print("*"*50)
**************************************************
```python
def calculate_ema(data, window):
ema = data.ewm(span=window, adjust=False).mean()
return ema
**************************************************
Reflection
The provided code for calculating the MACD (Moving Average Convergence
Divergence) is well-structured and easy to follow. Here are a few suggestions
for improvement:
22
1. **Documentation**: Add docstrings to functions `calculate_ema` and
`calculate_macd` to explain their purpose, parameters, and return values.
```python
def calculate_ema(data, window):
"""
Calculate Exponential Moving Average (EMA) of the given data.
Parameters:
data (pd.Series): The input data for EMA calculation.
window (int): The time window for EMA calculation.
Returns:
pd.Series: The EMA values.
"""
ema = data.ewm(span=window, adjust=False).mean()
return ema
Parameters:
data (pd.Series): The input data for MACD calculation.
short_window (int): The short-term EMA window (default is 12).
long_window (int): The long-term EMA window (default is 26).
signal_window (int): The signal line EMA window (default is 9).
Returns:
pd.Series, pd.Series: The MACD line and Signal line.
"""
# Calculate the short-term and long-term EMAs
ema_short_long = calculate_ema(data, [short_window, long_window])
23
return macd_line, signal_line
```
**************************************************
```python
def calculate_ema(data, windows):
"""
Calculate Exponential Moving Average (EMA) of the given data.
Parameters:
data (pd.Series): The input data for EMA calculation.
windows (list): List of time windows for EMA calculation.
Returns:
pd.Series: The EMA values.
"""
ema = data.ewm(span=windows, adjust=False).mean()
return ema
Parameters:
data (pd.Series): The input data for MACD calculation.
short_window (int): The short-term EMA window (default is 12).
long_window (int): The long-term EMA window (default is 26).
signal_window (int): The signal line EMA window (default is 9).
Returns:
pd.Series, pd.Series: The MACD line and Signal line.
"""
# Calculate the short-term and long-term EMAs
ema_short_long = calculate_ema(data, [short_window, long_window])
24
**************************************************
**************************************************
Reflection
The provided code for calculating the Moving Average Convergence Divergence
(MACD) is well-structured and follows PEP 8 guidelines. Here are a few
suggestions for improvement:
Here is the corrected code segment for calculating the MACD line:
```python
def calculate_macd(data, short_window=12, long_window=26, signal_window=9):
"""
Calculate Moving Average Convergence Divergence (MACD) and Signal Line.
Parameters:
data (pd.Series): The input data for MACD calculation.
short_window (int): The short-term EMA window (default is 12).
long_window (int): The long-term EMA window (default is 26).
signal_window (int): The signal line EMA window (default is 9).
Returns:
pd.Series, pd.Series: The MACD line and Signal line.
"""
# Calculate the short-term and long-term EMAs
ema_short = calculate_ema(data, short_window)
ema_long = calculate_ema(data, long_window)
25
```
This correction ensures that the MACD line is correctly calculated as the
difference between the short-term EMA and the long-term EMA.
**************************************************
```python
def calculate_macd(data, short_window=12, long_window=26, signal_window=9):
"""
Calculate Moving Average Convergence Divergence (MACD) and Signal Line.
Parameters:
data (pd.Series): The input data for MACD calculation.
short_window (int): The short-term EMA window (default is 12).
long_window (int): The long-term EMA window (default is 26).
signal_window (int): The signal line EMA window (default is 9).
Returns:
pd.Series, pd.Series: The MACD line and Signal line.
"""
# Calculate the short-term and long-term EMAs
ema_short = calculate_ema(data, short_window)
ema_long = calculate_ema(data, long_window)
**************************************************
**************************************************
Reflection
The provided code for calculating the Moving Average Convergence Divergence
(MACD) is well-structured and documented. However, there are a few areas that
can be improved:
26
2. The function could benefit from input validation to ensure that the `data`
parameter is a valid `pd.Series` object.
3. It might be helpful to add a brief description of the MACD line and Signal
line in the docstring for users unfamiliar with these concepts.
If you need assistance with the `calculate_ema` function or have any other
questions, feel free to ask.
**************************************************
```python
import pandas as pd
Parameters:
data (pd.Series): The input data for EMA calculation.
window (int): The EMA window.
Returns:
pd.Series: The EMA values.
"""
return data.ewm(span=window, adjust=False).mean()
Parameters:
data (pd.Series): The input data for MACD calculation.
short_window (int): The short-term EMA window (default is 12).
long_window (int): The long-term EMA window (default is 26).
signal_window (int): The signal line EMA window (default is 9).
Returns:
pd.Series, pd.Series: The MACD line and Signal line.
"""
27
# Validate input data
if not isinstance(data, pd.Series):
raise ValueError("Input data must be a valid pd.Series object.")
**************************************************
[29]: print(code)
```python
import pandas as pd
Parameters:
data (pd.Series): The input data for EMA calculation.
window (int): The EMA window.
Returns:
pd.Series: The EMA values.
"""
return data.ewm(span=window, adjust=False).mean()
Parameters:
data (pd.Series): The input data for MACD calculation.
short_window (int): The short-term EMA window (default is 12).
long_window (int): The long-term EMA window (default is 26).
signal_window (int): The signal line EMA window (default is 9).
28
Returns:
pd.Series, pd.Series: The MACD line and Signal line.
"""
# Validate input data
if not isinstance(data, pd.Series):
raise ValueError("Input data must be a valid pd.Series object.")
29