0% found this document useful (0 votes)
21 views

Reflection Agent Using LangChain For Trading Strategy

The document discusses using a LangChain model to generate and evaluate Python code for algorithmic trading strategies. It provides an example of code generation for the RSI strategy and reflects on areas for improvement in the generated code.

Uploaded by

Anshuman Ghosh
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
21 views

Reflection Agent Using LangChain For Trading Strategy

The document discusses using a LangChain model to generate and evaluate Python code for algorithmic trading strategies. It provides an example of code generation for the RSI strategy and reflects on areas for improvement in the generated code.

Uploaded by

Anshuman Ghosh
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 29

Reflection_Agent_LangChain_Trading_Strategy

April 23, 2024

1 Basic Reflection Agent With LangChain for Trading Strategies


Python Code Implementation
[1]:

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]: from langchain_core.messages import AIMessage, BaseMessage, HumanMessage


from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

[3]: from langchain_openai import ChatOpenAI

from google.colab import userdata


OPENAI_API_KEY = userdata.get('OPENAI_API_KEY')

2
llm = ChatOpenAI(model="gpt-3.5-turbo-0125", temperature=0,␣
↪api_key=OPENAI_API_KEY)

3 Initial Generate
3.0.1 Prompt generate

[4]: prompt_generate = """You are a Python code generator specializing in␣


↪algorithmic trading. Your main role is to provide Python code solutions that␣

↪are straightforward, efficient, and strictly follow Pythonic principles.␣

↪Your responses should strictly consist of executable Python code tailored to␣

↪algorithmic trading strategies.

Please adhere to these protocols:


- Generate a code that is simple, efficient, optimized and the most␣
↪understandable possible.

- 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.

- Avoid using non-existent built-in methods, such as np.rolling or pd.rolling,␣


↪in well-known libraries.

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"),
]
)

generate = prompt | llm

[6]: stratgies = ['MACD', 'RSI', "Stochastic oscillator"]

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)

[17]: strat_trd = stratgies[1]


query = f"Give me a Python code implementation of the {strat_trd}"

request = HumanMessage(
content = query
)

# response = generate.invoke({"messages": [request]})


# code = response.content
# print(code)

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

for i in range(n, len(prices) - 1):


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
```

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␣

↪and focused. Offer suggestions for areas needing clarity or reorganization.

- Check compliance with PEP 8 guidelines, including appropriate use of␣


↪whitespace, line length, and indentation. Identify any parts that require␣

↪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␣

↪modifications are needed.

- Evaluate the code’s efficiency, particularly in data manipulation and␣


↪mathematical computations. Identify any unnecessary computations or␣

↪inefficient data structures and suggest improvements.

- Refrain from using non-existent built-in methods in well-known libraries.


Your Feedback Protocol:
- If suggesting modifications, include the specific code segment and your␣
↪recommendations.

- If no suggestions are necessary, respond with only the relevant Python code,␣
↪omitting any explanatory text or descriptions.

"""

4.0.2 Reflect LLM


[18]: reflection_prompt = ChatPromptTemplate.from_messages(
[
(
"system",
prompt_reflection,
),
MessagesPlaceholder(variable_name="messages"),
]
)

reflect = reflection_prompt | llm

5
4.0.3 Run reflect LLM on [request, previously generated code]

[19]: reflection = ""


for chunk in reflect.stream({"messages": [request,␣
↪HumanMessage(content=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.

Here is the revised code incorporating the above suggestions:

```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.")

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

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

6
rs = avg_gain / avg_loss
rsi = 100 - (100 / (1 + rs))

return rsi
```

[20]: # # or without streaming:


# resp = reflect.invoke({"messages": [request, HumanMessage(content=code)]})
# print(resp.content)

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.")

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

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
```

[22]: # END = ""


# for chunk in generate.stream(
# {"messages": [request, AIMessage(content=code),␣
↪HumanMessage(content=reflection)]}

# ):
# 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)

Generator with feedback from Reflection


The provided code for calculating the Relative Strength Index (RSI) looks
correct and well-structured. It includes input validation, variable
initialization, and the iterative calculation of RSI components. This function

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")

deltas = [prices[i] - prices[i - 1] for i in range(1, len(prices))]


gains = [delta if delta > 0 else 0 for delta in deltas]
losses = [-delta if delta < 0 else 0 for delta in deltas]

avg_gain = sum(gains[:n]) / n
avg_loss = sum(losses[:n]) / n

rs = avg_gain / avg_loss if avg_loss != 0 else 0


rsi = 100 - (100 / (1 + rs))

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]

avg_gain = sum(gain[:window]) / window


avg_loss = sum(loss[:window]) / window

rs = avg_gain / avg_loss if avg_loss != 0 else 0


rsi = [100 - (100 / (1 + rs))]

for i in range(window, len(data) - 1):


avg_gain = (avg_gain * (window - 1) + gain[i]) / window
avg_loss = (avg_loss * (window - 1) + loss[i]) / window
rs = avg_gain / avg_loss if avg_loss != 0 else 0
rsi.append(100 - (100 / (1 + rs)))

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.

:param prices: List of prices


:param n: Number of periods to consider for RSI calculation (default is 14)
:return: List of RSI values
"""
deltas = np.diff(prices)
seed = deltas[:n+1]
up = seed[seed >= 0].sum() / n
down = -seed[seed < 0].sum() / n
rs = up / down
rsi = np.zeros_like(prices)

10
rsi[:n] = 100. - 100. / (1. + rs)

for i in range(n, len(prices)):


delta = deltas[i - 1]

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
```**************************************************

5.0.1 Final Code


[24]: print(reflection)

```python
def calculate_rsi(prices, n=14):
"""
Calculate the Relative Strength Index (RSI) for a given list of prices.

:param prices: List of prices


:param n: Number of periods to consider for RSI calculation (default is 14)
:return: List of RSI values
"""
deltas = np.diff(prices)
seed = deltas[:n+1]
up = seed[seed >= 0].sum() / n
down = -seed[seed < 0].sum() / n
rs = up / down
rsi = np.zeros_like(prices)
rsi[:n] = 100. - 100. / (1. + rs)

for i in range(n, len(prices)):


delta = deltas[i - 1]

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
```

6 The whole process


[ ]: stratgies = ['MACD', 'RSI', "Stochastic oscillator"]

6.1 Generator and Reflection Agents


[ ]: prompt_generate = """You are a Python code generator specializing in␣
↪algorithmic trading. Your main role is to provide Python code solutions that␣

↪are straightforward, efficient, and strictly follow Pythonic principles.␣

↪Your responses should strictly consist of executable Python code tailored to␣

↪algorithmic trading strategies.

Please adhere to these protocols:


- Generate a code that is simple, efficient, optimized and the most␣
↪understandable possible.

- 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.

- Avoid using non-existent built-in methods, such as np.rolling or pd.rolling,␣


↪in well-known libraries.

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"),
]
)

generate = prompt | llm

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␣

↪and focused. Offer suggestions for areas needing clarity or reorganization.

- Check compliance with PEP 8 guidelines, including appropriate use of␣


↪whitespace, line length, and indentation. Identify any parts that require␣

↪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␣

↪modifications are needed.

- Evaluate the code’s efficiency, particularly in data manipulation and␣


↪mathematical computations. Identify any unnecessary computations or␣

↪inefficient data structures and suggest improvements.

- Refrain from using non-existent built-in methods in well-known libraries.


Your Feedback Protocol:
- If suggesting modifications, include the specific code segment and your␣
↪recommendations.

- 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
]
)

reflect = reflection_prompt | llm

6.2 Loop Generator + Reflection: RSI


[25]: strat_trd = stratgies[1]
query = f"Give me a Python code implementation of the {strat_trd}"

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

for i in range(n, len(prices) - 1):


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
```
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.

Here is the updated code with the division by zero check:

```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

for i in range(n, len(prices) - 1):


avg_gain = (avg_gain * (n - 1) + gain[i]) / n
avg_loss = (avg_loss * (n - 1) + loss[i]) / n

rs = avg_gain / avg_loss if avg_loss != 0 else float('inf')


rsi = 100 - (100 / (1 + rs))

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

for i in range(n, len(prices) - 1):


avg_gain = (avg_gain * (n - 1) + gain[i]) / n
avg_loss = (avg_loss * (n - 1) + loss[i]) / n

rs = avg_gain / avg_loss if avg_loss != 0 else float('inf')


rsi = 100 - (100 / (1 + rs))

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.

Here is an updated version incorporating these suggestions:

```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

def calculate_avg_gain_loss(gain, loss, n):


avg_gain = sum(gain[:n]) / n
avg_loss = sum(loss[:n]) / n
for i in range(n, len(gain)):
avg_gain = (avg_gain * (n - 1) + gain[i]) / n
avg_loss = (avg_loss * (n - 1) + loss[i]) / n
return avg_gain, avg_loss

deltas = calculate_deltas(prices)
gain, loss = calculate_gain_loss(deltas)
avg_gain, avg_loss = calculate_avg_gain_loss(gain, loss, n)

rs = avg_gain / avg_loss if avg_loss != 0 else float('inf')


rsi = 100 - (100 / (1 + rs))

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

def calculate_avg_gain_loss(gain, loss, n):


avg_gain = sum(gain[:n]) / n
avg_loss = sum(loss[:n]) / n
for i in range(n, len(gain)):
avg_gain = (avg_gain * (n - 1) + gain[i]) / n
avg_loss = (avg_loss * (n - 1) + loss[i]) / n
return avg_gain, avg_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)

rs = avg_gain / avg_loss if avg_loss != 0 else float('inf')


rsi = 100 - (100 / (1 + rs))

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.

3. **Variable Naming**: Consider using more descriptive variable names to


enhance readability.

Here is the revised code incorporating these suggestions:

```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

def calculate_avg_gain_loss(gain, loss, n):


avg_gain = sum(gain[:n]) / n
avg_loss = sum(loss[:n]) / n
for i in range(n, len(gain)):
avg_gain = ((avg_gain * (n - 1)) + gain[i]) / n
avg_loss = ((avg_loss * (n - 1)) + loss[i]) / n
return avg_gain, avg_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

rsi = 100 - (100 / (1 + rs))

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

def calculate_avg_gain_loss(gain, loss, n, prev_avg_gain, prev_avg_loss):


avg_gain = prev_avg_gain
avg_loss = prev_avg_loss
for i in range(n, len(gain)):
avg_gain = ((avg_gain * (n - 1)) + gain[i]) / n
avg_loss = ((avg_loss * (n - 1)) + loss[i]) / n
return avg_gain, avg_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

rsi = 100 - (100 / (1 + rs))

return rsi
```**************************************************

6.3 Loop Generator + Reflection: MACD


[28]: strat_trd = stratgies[0]
query = f"Give me a Python code implementation of the {strat_trd}"
print(f"Query: {query}\n")
print("*"*50)

request = HumanMessage(
content = query
)

print("\nFirst Code proposition by the Generator:\n")


code = ""
for chunk in generate.stream({"messages": [request]}):
print(chunk.content, end="")
code += chunk.content

#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)

Query: Give me a Python code implementation of the MACD

**************************************************

First Code proposition by the Generator:

```python
def calculate_ema(data, window):
ema = data.ewm(span=window, adjust=False).mean()
return ema

def calculate_macd(data, short_window=12, long_window=26, signal_window=9):


# Calculate the short-term EMA
ema_short = calculate_ema(data, short_window)

# Calculate the long-term EMA


ema_long = calculate_ema(data, long_window)

# Calculate the MACD line


macd_line = ema_short - ema_long

# Calculate the signal line


signal_line = calculate_ema(macd_line, signal_window)

return macd_line, signal_line


```

**************************************************

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.

2. **Variable Naming**: Consider using more descriptive variable names to


enhance readability. For example, `ema_short` could be renamed to `short_ema`.

3. **Efficiency**: Since the `calculate_ema` function is called twice with the


same `data` parameter, you can optimize the code by calculating both short-term
and long-term EMAs in a single function call.

Here is the revised code incorporating these suggestions:

```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

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_long = calculate_ema(data, [short_window, long_window])

# Calculate the MACD line


macd_line = ema_short_long[0] - ema_short_long[1]

# Calculate the signal line


signal_line = calculate_ema(macd_line, signal_window)

23
return macd_line, signal_line
```

**************************************************

Generator with feedback from Reflection

```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

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_long = calculate_ema(data, [short_window, long_window])

# Calculate the MACD line


macd_line = ema_short_long[0] - ema_short_long[1]

# Calculate the signal line


signal_line = calculate_ema(macd_line, signal_window)

return macd_line, signal_line


```

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:

1. **Documentation**: The docstrings provided for the functions are informative


and follow the necessary format. Good job on that!

2. **Functionality**: The implementation seems correct in terms of calculating


the MACD and Signal Line. However, there is a small issue in the calculation of
the MACD line. The MACD line should be the difference between the short-term EMA
and the long-term EMA, not the difference between the two EMAs directly.

3. **Efficiency**: The code is efficient in terms of data manipulation and


mathematical computations.

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)

# Calculate the MACD line


macd_line = ema_short - ema_long

# Calculate the signal line


signal_line = calculate_ema(macd_line, signal_window)

return macd_line, signal_line

25
```

This correction ensures that the MACD line is correctly calculated as the
difference between the short-term EMA and the long-term EMA.

**************************************************

Generator with feedback from Reflection

```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)

# Calculate the MACD line


macd_line = ema_short - ema_long

# Calculate the signal line


signal_line = calculate_ema(macd_line, signal_window)

return macd_line, signal_line


```

**************************************************

**************************************************

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:

1. It would be beneficial to include the implementation of the `calculate_ema`


function or ensure it is imported from a module for the code to be executable.

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.

Overall, the code is clear and follows good practices.

If the `calculate_ema` function is implemented correctly, the code is good to


go.

If you need assistance with the `calculate_ema` function or have any other
questions, feel free to ask.

**************************************************

Generator with feedback from Reflection

```python
import pandas as pd

def calculate_ema(data, window):


"""
Calculate Exponential Moving Average (EMA).

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()

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.
"""

27
# Validate input data
if not isinstance(data, pd.Series):
raise ValueError("Input data must be a valid pd.Series object.")

# Calculate the short-term and long-term EMAs


ema_short = calculate_ema(data, short_window)
ema_long = calculate_ema(data, long_window)

# Calculate the MACD line


macd_line = ema_short - ema_long

# Calculate the signal line


signal_line = calculate_ema(macd_line, signal_window)

return macd_line, signal_line


```

**************************************************

6.3.1 Final Code/ macd

[29]: print(code)

```python
import pandas as pd

def calculate_ema(data, window):


"""
Calculate Exponential Moving Average (EMA).

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()

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).

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.")

# Calculate the short-term and long-term EMAs


ema_short = calculate_ema(data, short_window)
ema_long = calculate_ema(data, long_window)

# Calculate the MACD line


macd_line = ema_short - ema_long

# Calculate the signal line


signal_line = calculate_ema(macd_line, signal_window)

return macd_line, signal_line


```

29

You might also like