working code
Browse files- README.md +43 -0
- app.py +66 -16
- instructions.md +23 -0
README.md
CHANGED
@@ -10,3 +10,46 @@ pinned: false
|
|
10 |
---
|
11 |
|
12 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
---
|
11 |
|
12 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
13 |
+
**Overview:**
|
14 |
+
|
15 |
+
This Python code implements a forex trading tool that combines technical analysis with sentiment analysis to generate trading signals. It leverages the Backtrader library for backtesting, the Alpha Vantage API for fetching forex data and sentiment data, and Gradio for creating a user-friendly interface.
|
16 |
+
|
17 |
+
**Key Features:**
|
18 |
+
|
19 |
+
- **Trend-following strategy:** Employs a simple moving average crossover strategy to identify potential buy and sell signals.
|
20 |
+
- **Sentiment analysis:** Incorporates sentiment analysis from news data to refine trade decisions.
|
21 |
+
- **Backtesting capabilities:** Allows users to test the strategy's performance on historical data.
|
22 |
+
- **User-friendly interface:** Provides a Gradio interface for easy interaction and visualization of results.
|
23 |
+
|
24 |
+
**Code Structure:**
|
25 |
+
|
26 |
+
1. **Import Necessary Libraries:**
|
27 |
+
- `gradio`, `pandas`, `backtrader`, `requests`
|
28 |
+
2. **Define Instructions:**
|
29 |
+
- Reads Markdown-formatted instructions from a file for user guidance.
|
30 |
+
3. **TrendFollowingStrategy Class:**
|
31 |
+
- Implements the trend-following strategy logic using a moving average crossover.
|
32 |
+
- Tracks trade details (count, wins, losses) and logs trade information.
|
33 |
+
4. **Data Fetching Functions:**
|
34 |
+
- `fetch_forex_intraday`: Retrieves forex data from Alpha Vantage.
|
35 |
+
- `fetch_sentiment_data`: Fetches sentiment data from Alpha Vantage.
|
36 |
+
- `analyze_sentiment`: Analyzes sentiment data for a given ticker.
|
37 |
+
- `load_data`: Converts fetched data into a Backtrader data feed.
|
38 |
+
5. **Trade Decision Function:**
|
39 |
+
- `should_trade`: Determines whether to make a trade based on technical signals and sentiment analysis.
|
40 |
+
6. **Backtesting Function:**
|
41 |
+
- `run_backtest`: Runs a backtest using specified parameters and returns performance statistics and trade decisions.
|
42 |
+
7. **Interface Creation:**
|
43 |
+
- Sets up Gradio interface elements for user input and output.
|
44 |
+
- Launches the interface, allowing users to interact with the tool.
|
45 |
+
|
46 |
+
**How to Use:**
|
47 |
+
|
48 |
+
1. Obtain an API key from Alpha Vantage.
|
49 |
+
2. Run the Python code.
|
50 |
+
3. Enter your API key in the Gradio interface.
|
51 |
+
4. Select the desired currency pair and time interval.
|
52 |
+
5. Click the "Run" button to initiate the backtest.
|
53 |
+
6. Review the generated backtest results and trade decisions.
|
54 |
+
|
55 |
+
|
app.py
CHANGED
@@ -3,6 +3,11 @@ import pandas as pd
|
|
3 |
import backtrader as bt
|
4 |
import requests
|
5 |
|
|
|
|
|
|
|
|
|
|
|
6 |
class TrendFollowingStrategy(bt.Strategy):
|
7 |
params = (('ma_period', 15),)
|
8 |
|
@@ -16,6 +21,7 @@ class TrendFollowingStrategy(bt.Strategy):
|
|
16 |
self.trade_count = 0
|
17 |
self.win_count = 0
|
18 |
self.loss_count = 0
|
|
|
19 |
|
20 |
def next(self):
|
21 |
# Check if we are in the market
|
@@ -36,7 +42,6 @@ class TrendFollowingStrategy(bt.Strategy):
|
|
36 |
# We are short and get a buy signal
|
37 |
self.close() # Close the short position
|
38 |
|
39 |
-
|
40 |
def notify_trade(self, trade):
|
41 |
if trade.isclosed:
|
42 |
outcome = 'win' if trade.pnl > 0 else 'loss'
|
@@ -51,8 +56,21 @@ class TrendFollowingStrategy(bt.Strategy):
|
|
51 |
self.win_count += 1
|
52 |
elif outcome == 'loss':
|
53 |
self.loss_count += 1
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
print(f"Trade {self.trade_count}: {trade_type} - {outcome}")
|
55 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
def fetch_forex_intraday(api_key, from_symbol, to_symbol, interval, outputsize='compact'):
|
57 |
url = f'https://www.alphavantage.co/query?function=FX_INTRADAY&from_symbol={from_symbol}&to_symbol={to_symbol}&interval={interval}&apikey={api_key}&outputsize={outputsize}'
|
58 |
response = requests.get(url)
|
@@ -184,8 +202,8 @@ def should_trade(strategy, api_endpoint, api_key, base_currency, quote_currency)
|
|
184 |
|
185 |
# Fetch and analyze sentiment data
|
186 |
json_response = fetch_sentiment_data(api_endpoint, f"{base_ticker}", api_key)
|
187 |
-
print(fetch_sentiment_data(api_endpoint, f"{quote_currency}", api_key))
|
188 |
-
print(json_response)
|
189 |
base_sentiment = analyze_sentiment(json_response, base_ticker)
|
190 |
quote_sentiment = analyze_sentiment(json_response, quote_currency)
|
191 |
|
@@ -198,7 +216,8 @@ def should_trade(strategy, api_endpoint, api_key, base_currency, quote_currency)
|
|
198 |
return True, trade_decision, timeframe, decision_reason
|
199 |
return False, None, None, "Not enough consistent signals or conflicting sentiment " +decision_reason+"."
|
200 |
|
201 |
-
|
|
|
202 |
def run_backtest(api_key, from_symbol, to_symbol, interval):
|
203 |
# Set up Cerebro engine
|
204 |
cerebro = bt.Cerebro()
|
@@ -231,7 +250,39 @@ def run_backtest(api_key, from_symbol, to_symbol, interval):
|
|
231 |
signal = "Sell"
|
232 |
color = "red"
|
233 |
|
234 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
235 |
|
236 |
|
237 |
# Define a list of popular currency pairs for the dropdowns
|
@@ -241,18 +292,17 @@ to_currency_choices = ['USD', 'JPY', 'GBP', 'AUD', 'CAD']
|
|
241 |
# Placeholder link for API key
|
242 |
api_key_link = "https://www.alphavantage.co/support/#api-key"
|
243 |
|
244 |
-
|
245 |
-
|
|
|
|
|
|
|
246 |
gr.Interface(
|
247 |
fn=run_backtest,
|
248 |
-
inputs=[
|
249 |
-
gr.inputs.Textbox(label="API Key", placeholder="Enter your API key"),
|
250 |
-
gr.inputs.Dropdown(label="From Currency", choices=['EUR', 'GBP', 'USD', 'AUD', 'JPY']),
|
251 |
-
gr.inputs.Dropdown(label="To Currency", choices=['USD', 'JPY', 'GBP', 'AUD', 'CAD']),
|
252 |
-
gr.inputs.Radio(label="Interval", choices=["1min", "5min", "15min", "30min", "60min"])
|
253 |
-
],
|
254 |
outputs="html",
|
255 |
live=True,
|
256 |
-
title="Trading
|
257 |
-
description=
|
258 |
-
|
|
|
|
3 |
import backtrader as bt
|
4 |
import requests
|
5 |
|
6 |
+
|
7 |
+
# Define the Markdown-formatted instructions
|
8 |
+
with open("instructions.md", "r") as md_file:
|
9 |
+
instructions = md_file.read()
|
10 |
+
|
11 |
class TrendFollowingStrategy(bt.Strategy):
|
12 |
params = (('ma_period', 15),)
|
13 |
|
|
|
21 |
self.trade_count = 0
|
22 |
self.win_count = 0
|
23 |
self.loss_count = 0
|
24 |
+
self.trade_log = [] # Store trade details as a list of dictionaries
|
25 |
|
26 |
def next(self):
|
27 |
# Check if we are in the market
|
|
|
42 |
# We are short and get a buy signal
|
43 |
self.close() # Close the short position
|
44 |
|
|
|
45 |
def notify_trade(self, trade):
|
46 |
if trade.isclosed:
|
47 |
outcome = 'win' if trade.pnl > 0 else 'loss'
|
|
|
56 |
self.win_count += 1
|
57 |
elif outcome == 'loss':
|
58 |
self.loss_count += 1
|
59 |
+
trade_details = {
|
60 |
+
'trade_num': self.trade_count,
|
61 |
+
'trade_type': trade_type,
|
62 |
+
'outcome': outcome
|
63 |
+
}
|
64 |
+
self.trade_log.append(trade_details)
|
65 |
print(f"Trade {self.trade_count}: {trade_type} - {outcome}")
|
66 |
|
67 |
+
def get_trade_log(self):
|
68 |
+
"""
|
69 |
+
Get the trade log as a list of dictionaries.
|
70 |
+
"""
|
71 |
+
return self.trade_log
|
72 |
+
|
73 |
+
|
74 |
def fetch_forex_intraday(api_key, from_symbol, to_symbol, interval, outputsize='compact'):
|
75 |
url = f'https://www.alphavantage.co/query?function=FX_INTRADAY&from_symbol={from_symbol}&to_symbol={to_symbol}&interval={interval}&apikey={api_key}&outputsize={outputsize}'
|
76 |
response = requests.get(url)
|
|
|
202 |
|
203 |
# Fetch and analyze sentiment data
|
204 |
json_response = fetch_sentiment_data(api_endpoint, f"{base_ticker}", api_key)
|
205 |
+
#print(fetch_sentiment_data(api_endpoint, f"{quote_currency}", api_key))
|
206 |
+
#print(json_response)
|
207 |
base_sentiment = analyze_sentiment(json_response, base_ticker)
|
208 |
quote_sentiment = analyze_sentiment(json_response, quote_currency)
|
209 |
|
|
|
216 |
return True, trade_decision, timeframe, decision_reason
|
217 |
return False, None, None, "Not enough consistent signals or conflicting sentiment " +decision_reason+"."
|
218 |
|
219 |
+
import backtrader as bt
|
220 |
+
|
221 |
def run_backtest(api_key, from_symbol, to_symbol, interval):
|
222 |
# Set up Cerebro engine
|
223 |
cerebro = bt.Cerebro()
|
|
|
250 |
signal = "Sell"
|
251 |
color = "red"
|
252 |
|
253 |
+
# Get trade decision information
|
254 |
+
trade_decision, trade_type, trade_timeframe, reason = should_trade(strategy_instance, api_endpoint, api_key, from_symbol, to_symbol)
|
255 |
+
|
256 |
+
|
257 |
+
# Create an HTML message with the calculated statistics, trade log, and trade decision information
|
258 |
+
html_message = f"""
|
259 |
+
<p><strong>Strategy Performance Summary:</strong></p>
|
260 |
+
<p>On the {interval} timeframe</p>
|
261 |
+
<p>*****************************</p>
|
262 |
+
<p>Total Trades: {total_trades}</p>
|
263 |
+
<p>Total Wins: {total_wins} ({win_percentage:.2f}%)</p>
|
264 |
+
<p>Total Losses: {total_losses} ({loss_percentage:.2f}%)</p>
|
265 |
+
<p>Signal: <span style='color: {color}'>{signal}</span></p>
|
266 |
+
<p><strong>Trade Log:</strong></p>
|
267 |
+
<ul>
|
268 |
+
"""
|
269 |
+
# Get trade log from the strategy
|
270 |
+
trade_log = strategy_instance.get_trade_log()
|
271 |
+
|
272 |
+
for trade in trade_log:
|
273 |
+
html_message += f"<li>Trade {trade['trade_num']}: {trade['trade_type']} - {trade['outcome']}</li>"
|
274 |
+
|
275 |
+
html_message += "</ul>"
|
276 |
+
|
277 |
+
# Include trade decision information
|
278 |
+
html_message += f"""
|
279 |
+
<p><strong>Trade Decision:</strong></p>
|
280 |
+
<p>Trade Type: {trade_type}</p>
|
281 |
+
<p>Timeframe: {trade_timeframe}</p>
|
282 |
+
<p>Reason: {reason}</p>
|
283 |
+
"""
|
284 |
+
|
285 |
+
return html_message
|
286 |
|
287 |
|
288 |
# Define a list of popular currency pairs for the dropdowns
|
|
|
292 |
# Placeholder link for API key
|
293 |
api_key_link = "https://www.alphavantage.co/support/#api-key"
|
294 |
|
295 |
+
api_key_input = gr.Textbox(label="API Key", placeholder="Enter your API key")
|
296 |
+
from_currency_input = gr.Dropdown(label="From Currency", choices=['EUR', 'GBP', 'USD', 'AUD', 'JPY'])
|
297 |
+
to_currency_input = gr.Dropdown(label="To Currency", choices=['USD', 'JPY', 'GBP', 'AUD', 'CAD'])
|
298 |
+
interval_input = gr.Radio(label="Interval", choices=["1min", "5min", "15min", "30min", "60min"])
|
299 |
+
|
300 |
gr.Interface(
|
301 |
fn=run_backtest,
|
302 |
+
inputs=[api_key_input, from_currency_input, to_currency_input, interval_input],
|
|
|
|
|
|
|
|
|
|
|
303 |
outputs="html",
|
304 |
live=True,
|
305 |
+
title="Forex Trend Trading Signals",
|
306 |
+
description=instructions,
|
307 |
+
cache_examples=True
|
308 |
+
).launch()
|
instructions.md
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
### Purpose:
|
2 |
+
This script is for research purposes only and is not intended for actual trading. It demonstrates how to use the AlphaVantage API to perform backtesting and generate trading signals.
|
3 |
+
|
4 |
+
### Instructions:
|
5 |
+
1. **Get Your API Key:**
|
6 |
+
- Sign up for an API key on the [AlphaVantage website](https://www.alphavantage.co/).
|
7 |
+
- Enter your API key in the 'API Key' field.
|
8 |
+
|
9 |
+
2. **Select Currency Pairs:**
|
10 |
+
- Choose the 'From Currency' and 'To Currency' from the dropdown menus.
|
11 |
+
|
12 |
+
3. **Choose Interval:**
|
13 |
+
- Select the 'Interval' for your backtest.
|
14 |
+
|
15 |
+
4. **Run Backtest:**
|
16 |
+
- Click 'Submit' to run the backtest and get trading signals.
|
17 |
+
|
18 |
+
|
19 |
+
Code Documentation
|
20 |
+
------------------
|
21 |
+
[README.md](README.md)
|
22 |
+
---
|
23 |
+
|