goldhand 20.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- goldhand-20.3/PKG-INFO +199 -0
- goldhand-20.3/README.md +172 -0
- goldhand-20.3/goldhand/__init__.py +9 -0
- goldhand-20.3/goldhand/backtest.py +168 -0
- goldhand-20.3/goldhand/data.py +68 -0
- goldhand-20.3/goldhand/indicators.py +226 -0
- goldhand-20.3/goldhand/plotting.py +182 -0
- goldhand-20.3/goldhand/stocks.py +150 -0
- goldhand-20.3/goldhand/strategies/__init__.py +3 -0
- goldhand-20.3/goldhand/strategies/adaptive_trend.py +242 -0
- goldhand-20.3/goldhand/strategies/goldhand_line.py +128 -0
- goldhand-20.3/goldhand/strategies/rsi.py +139 -0
- goldhand-20.3/goldhand/tw.py +217 -0
- goldhand-20.3/goldhand.egg-info/PKG-INFO +199 -0
- goldhand-20.3/goldhand.egg-info/SOURCES.txt +18 -0
- goldhand-20.3/goldhand.egg-info/dependency_links.txt +1 -0
- goldhand-20.3/goldhand.egg-info/requires.txt +9 -0
- goldhand-20.3/goldhand.egg-info/top_level.txt +1 -0
- goldhand-20.3/setup.cfg +4 -0
- goldhand-20.3/setup.py +24 -0
goldhand-20.3/PKG-INFO
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: goldhand
|
|
3
|
+
Version: 20.3
|
|
4
|
+
Summary: A package working with financial data
|
|
5
|
+
Home-page: https://github.com/misrori/goldhand
|
|
6
|
+
Author: Mihaly
|
|
7
|
+
Author-email: ormraat.pte@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
Requires-Dist: pandas
|
|
11
|
+
Requires-Dist: plotly
|
|
12
|
+
Requires-Dist: scipy
|
|
13
|
+
Requires-Dist: numpy
|
|
14
|
+
Requires-Dist: numba
|
|
15
|
+
Requires-Dist: requests
|
|
16
|
+
Requires-Dist: tqdm
|
|
17
|
+
Requires-Dist: yfinance<1.0
|
|
18
|
+
Requires-Dist: ipython
|
|
19
|
+
Dynamic: author
|
|
20
|
+
Dynamic: author-email
|
|
21
|
+
Dynamic: description
|
|
22
|
+
Dynamic: description-content-type
|
|
23
|
+
Dynamic: home-page
|
|
24
|
+
Dynamic: license
|
|
25
|
+
Dynamic: requires-dist
|
|
26
|
+
Dynamic: summary
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# [Goldhand](https://github.com/misrori/goldhand)
|
|
30
|
+
The ultimate python package to work with stock and crypto data
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install goldhand
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# [TradingView]((https://github.com/misrori/goldhand/tw.py))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
from goldhand import *
|
|
42
|
+
|
|
43
|
+
# tradingView data
|
|
44
|
+
tw = Tw()
|
|
45
|
+
|
|
46
|
+
# data frame of the stocks
|
|
47
|
+
tw.stock
|
|
48
|
+
|
|
49
|
+
# data frame of the top 300 crypto currency
|
|
50
|
+
tw.crypto
|
|
51
|
+
|
|
52
|
+
# data frame of the top 3000 etf
|
|
53
|
+
tw.etf
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
# Get a plot of the stock to see the location in the sector
|
|
59
|
+
tw.get_sec_plot('AMD').show()
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+

|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
# Get a plot of the stock to see the location in the industry
|
|
67
|
+
tw.get_sec_plot('AMD').show()
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+

|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# [Goldhand class](https://github.com/misrori/goldhand/stock.py)
|
|
75
|
+
|
|
76
|
+
The `GoldHand` class is a part of the `goldhand` Python package, which provides functionality for working with stock and crypto data. This class allows users to retrieve detailed information and charts for a specific stock.
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
|
|
82
|
+
# Get a detailed chart of a stock AMD
|
|
83
|
+
ticker = "AMD"
|
|
84
|
+
t = GoldHand(ticker)
|
|
85
|
+
t.df.tail().T
|
|
86
|
+
```
|
|
87
|
+

|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
|
|
92
|
+
# Get a detailed chart of a stock AMD
|
|
93
|
+
ticker = "TSLA"
|
|
94
|
+
t = GoldHand(ticker)
|
|
95
|
+
t.plotly_last_year(tw.get_plotly_title(ticker)).show()
|
|
96
|
+
|
|
97
|
+
## Stock Chart
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+

|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
|
|
104
|
+
# Get a detailed chart of a crypto
|
|
105
|
+
ticker = "BTC-USD"
|
|
106
|
+
t = GoldHand(ticker)
|
|
107
|
+
t.plotly_last_year(tw.get_plotly_title(ticker)).show()
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+

|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
## [GoldHand Line indicator](https://gist.github.com/misrori/ae77642c31fb1a973c7627cc077a1df2)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
ticker = "TSLA"
|
|
119
|
+
t = GoldHand(ticker)
|
|
120
|
+
t.plot_goldhand_line(tw.get_plotly_title(ticker)).show()
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+

|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
# [Backtest](https://github.com/misrori/goldhand/backtest.py)
|
|
128
|
+
|
|
129
|
+
The Backtest class is a powerful tool for evaluating the performance of trading strategies using historical data. It allows you to simulate trades and calculate various performance metrics to assess the profitability and risk of your strategy.
|
|
130
|
+
|
|
131
|
+
It takes a data and a function and display the trades.
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
ticker= 'TSLA'
|
|
137
|
+
data = GoldHand(ticker).df
|
|
138
|
+
backtest = Backtest( data, rsi_strategy, plot_title=tw.get_plotly_title(ticker), buy_threshold=30, sell_threshold=70)
|
|
139
|
+
backtest.summarize_strategy()
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
`summarize_strategy` will show the trades summary, a plot with trades and the trades in DataFrame.
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+

|
|
146
|
+
|
|
147
|
+

|
|
148
|
+
|
|
149
|
+

|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
# Strategys
|
|
153
|
+
|
|
154
|
+
## [RSI Strategy](https://github.com/misrori/goldhand/strategy_rsi.py)
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
"""
|
|
158
|
+
RSI strategy for backtesting with Backtest class
|
|
159
|
+
|
|
160
|
+
Parameters:
|
|
161
|
+
- data: pandas DataFrame with columns: date, open, high, low, close, volume and rsi
|
|
162
|
+
- buy_threshold: int, default 30, buy when RSI is below this value
|
|
163
|
+
- sell_threshold: int, default 70, sell when RSI is above this value
|
|
164
|
+
"""
|
|
165
|
+
backtest = Backtest( data, rsi_strategy, plot_title=tw.get_plotly_title(ticker), buy_threshold=30, sell_threshold=70)
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
ticker = 'TSLA'
|
|
172
|
+
p = show_indicator_rsi_strategy(ticker = ticker, buy_threshold=30, sell_threshold=70, plot_title=tw.get_plotly_title(ticker), add_strategy_summary=True)
|
|
173
|
+
```
|
|
174
|
+

|
|
175
|
+
|
|
176
|
+
## [GoldHand Line indicator](https://github.com/misrori/goldhand/strategy_goldhand_line.py)
|
|
177
|
+
|
|
178
|
+
```python
|
|
179
|
+
"""
|
|
180
|
+
This function implements the GoldHandLine strategy.
|
|
181
|
+
|
|
182
|
+
Parameters:
|
|
183
|
+
- data (pandas DataFrame) : The DataFrame containing the data.
|
|
184
|
+
- buy_at (str): The color of the line to buy at. Default is 'gold'.
|
|
185
|
+
- sell_at (str): The color of the line to sell at. Default is 'grey'.
|
|
186
|
+
|
|
187
|
+
"""
|
|
188
|
+
backtest = Backtest( data, goldhand_line_strategy,)
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
```python
|
|
193
|
+
ticker = 'BTC-USD'
|
|
194
|
+
show_indicator_goldhand_line_strategy(ticker = ticker, plot_title=tw.get_plotly_title(ticker), buy_at='gold', sell_at='blue', add_strategy_summary=True)
|
|
195
|
+
```
|
|
196
|
+

|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
|
goldhand-20.3/README.md
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
|
|
2
|
+
# [Goldhand](https://github.com/misrori/goldhand)
|
|
3
|
+
The ultimate python package to work with stock and crypto data
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install goldhand
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# [TradingView]((https://github.com/misrori/goldhand/tw.py))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from goldhand import *
|
|
15
|
+
|
|
16
|
+
# tradingView data
|
|
17
|
+
tw = Tw()
|
|
18
|
+
|
|
19
|
+
# data frame of the stocks
|
|
20
|
+
tw.stock
|
|
21
|
+
|
|
22
|
+
# data frame of the top 300 crypto currency
|
|
23
|
+
tw.crypto
|
|
24
|
+
|
|
25
|
+
# data frame of the top 3000 etf
|
|
26
|
+
tw.etf
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
```python
|
|
31
|
+
# Get a plot of the stock to see the location in the sector
|
|
32
|
+
tw.get_sec_plot('AMD').show()
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+

|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
# Get a plot of the stock to see the location in the industry
|
|
40
|
+
tw.get_sec_plot('AMD').show()
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+

|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
# [Goldhand class](https://github.com/misrori/goldhand/stock.py)
|
|
48
|
+
|
|
49
|
+
The `GoldHand` class is a part of the `goldhand` Python package, which provides functionality for working with stock and crypto data. This class allows users to retrieve detailed information and charts for a specific stock.
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
|
|
55
|
+
# Get a detailed chart of a stock AMD
|
|
56
|
+
ticker = "AMD"
|
|
57
|
+
t = GoldHand(ticker)
|
|
58
|
+
t.df.tail().T
|
|
59
|
+
```
|
|
60
|
+

|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
|
|
65
|
+
# Get a detailed chart of a stock AMD
|
|
66
|
+
ticker = "TSLA"
|
|
67
|
+
t = GoldHand(ticker)
|
|
68
|
+
t.plotly_last_year(tw.get_plotly_title(ticker)).show()
|
|
69
|
+
|
|
70
|
+
## Stock Chart
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+

|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
|
|
77
|
+
# Get a detailed chart of a crypto
|
|
78
|
+
ticker = "BTC-USD"
|
|
79
|
+
t = GoldHand(ticker)
|
|
80
|
+
t.plotly_last_year(tw.get_plotly_title(ticker)).show()
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+

|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
## [GoldHand Line indicator](https://gist.github.com/misrori/ae77642c31fb1a973c7627cc077a1df2)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
ticker = "TSLA"
|
|
92
|
+
t = GoldHand(ticker)
|
|
93
|
+
t.plot_goldhand_line(tw.get_plotly_title(ticker)).show()
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+

|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
# [Backtest](https://github.com/misrori/goldhand/backtest.py)
|
|
101
|
+
|
|
102
|
+
The Backtest class is a powerful tool for evaluating the performance of trading strategies using historical data. It allows you to simulate trades and calculate various performance metrics to assess the profitability and risk of your strategy.
|
|
103
|
+
|
|
104
|
+
It takes a data and a function and display the trades.
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
ticker= 'TSLA'
|
|
110
|
+
data = GoldHand(ticker).df
|
|
111
|
+
backtest = Backtest( data, rsi_strategy, plot_title=tw.get_plotly_title(ticker), buy_threshold=30, sell_threshold=70)
|
|
112
|
+
backtest.summarize_strategy()
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
`summarize_strategy` will show the trades summary, a plot with trades and the trades in DataFrame.
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+

|
|
119
|
+
|
|
120
|
+

|
|
121
|
+
|
|
122
|
+

|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
# Strategys
|
|
126
|
+
|
|
127
|
+
## [RSI Strategy](https://github.com/misrori/goldhand/strategy_rsi.py)
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
"""
|
|
131
|
+
RSI strategy for backtesting with Backtest class
|
|
132
|
+
|
|
133
|
+
Parameters:
|
|
134
|
+
- data: pandas DataFrame with columns: date, open, high, low, close, volume and rsi
|
|
135
|
+
- buy_threshold: int, default 30, buy when RSI is below this value
|
|
136
|
+
- sell_threshold: int, default 70, sell when RSI is above this value
|
|
137
|
+
"""
|
|
138
|
+
backtest = Backtest( data, rsi_strategy, plot_title=tw.get_plotly_title(ticker), buy_threshold=30, sell_threshold=70)
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
ticker = 'TSLA'
|
|
145
|
+
p = show_indicator_rsi_strategy(ticker = ticker, buy_threshold=30, sell_threshold=70, plot_title=tw.get_plotly_title(ticker), add_strategy_summary=True)
|
|
146
|
+
```
|
|
147
|
+

|
|
148
|
+
|
|
149
|
+
## [GoldHand Line indicator](https://github.com/misrori/goldhand/strategy_goldhand_line.py)
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
"""
|
|
153
|
+
This function implements the GoldHandLine strategy.
|
|
154
|
+
|
|
155
|
+
Parameters:
|
|
156
|
+
- data (pandas DataFrame) : The DataFrame containing the data.
|
|
157
|
+
- buy_at (str): The color of the line to buy at. Default is 'gold'.
|
|
158
|
+
- sell_at (str): The color of the line to sell at. Default is 'grey'.
|
|
159
|
+
|
|
160
|
+
"""
|
|
161
|
+
backtest = Backtest( data, goldhand_line_strategy,)
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
ticker = 'BTC-USD'
|
|
167
|
+
show_indicator_goldhand_line_strategy(ticker = ticker, plot_title=tw.get_plotly_title(ticker), buy_at='gold', sell_at='blue', add_strategy_summary=True)
|
|
168
|
+
```
|
|
169
|
+

|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from goldhand.stocks import GoldHand
|
|
2
|
+
from goldhand.backtest import Backtest
|
|
3
|
+
from goldhand.data import Data
|
|
4
|
+
from goldhand.indicators import Indicators
|
|
5
|
+
from goldhand.plotting import Plotting
|
|
6
|
+
from goldhand.tw import Tw
|
|
7
|
+
from goldhand.strategies import goldhand_line_strategy, show_indicator_goldhand_line_strategy
|
|
8
|
+
from goldhand.strategies import rsi_strategy, show_indicator_rsi_strategy
|
|
9
|
+
from goldhand.strategies import adaptive_trend_strategy, show_indicator_adaptive_trend_strategy
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
from IPython.display import display
|
|
2
|
+
import pandas as pd
|
|
3
|
+
import numpy as np
|
|
4
|
+
from goldhand.plotting import Plotting
|
|
5
|
+
|
|
6
|
+
class Backtest:
|
|
7
|
+
"""
|
|
8
|
+
Backtest class for running trading strategies.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
def __init__(self, data, strategy_func, plot_title='Backtest', **kwargs):
|
|
12
|
+
"""
|
|
13
|
+
Initialize backtest.
|
|
14
|
+
|
|
15
|
+
Parameters:
|
|
16
|
+
- data: DataFrame with OHLCV data
|
|
17
|
+
- strategy_func: Function that takes data and returns trades DataFrame
|
|
18
|
+
- plot_title: Title for plots
|
|
19
|
+
- **kwargs: Additional parameters to pass to strategy function
|
|
20
|
+
"""
|
|
21
|
+
self.data = data.copy()
|
|
22
|
+
self.strategy_func = strategy_func
|
|
23
|
+
self.plot_title = plot_title
|
|
24
|
+
self.additional_params = kwargs
|
|
25
|
+
|
|
26
|
+
# Run strategy
|
|
27
|
+
self.trades = self.strategy_func(self.data, **kwargs)
|
|
28
|
+
|
|
29
|
+
# Ensure trades is a DataFrame
|
|
30
|
+
if not isinstance(self.trades, pd.DataFrame):
|
|
31
|
+
self.trades = pd.DataFrame()
|
|
32
|
+
|
|
33
|
+
# Reorder columns for better readability
|
|
34
|
+
if not self.trades.empty:
|
|
35
|
+
first = ['ticker', 'buy_price', 'buy_date', 'trade_id', 'status', 'sell_price', 'sell_date', 'result', 'days_in_trade']
|
|
36
|
+
all_col = list(self.trades.columns)
|
|
37
|
+
first = [x for x in first if x in all_col]
|
|
38
|
+
first.extend([x for x in all_col if x not in first])
|
|
39
|
+
self.trades = self.trades[first]
|
|
40
|
+
|
|
41
|
+
self.calculate_summary()
|
|
42
|
+
|
|
43
|
+
def calculate_summary(self):
|
|
44
|
+
"""
|
|
45
|
+
Calculate comprehensive performance metrics.
|
|
46
|
+
"""
|
|
47
|
+
if self.trades.empty:
|
|
48
|
+
self.trades_summary = {'number_of_trades': 0}
|
|
49
|
+
self.trade_summary_plot_text = "No trades executed."
|
|
50
|
+
return
|
|
51
|
+
|
|
52
|
+
# Explicit type conversion to numeric to avoid errors
|
|
53
|
+
results = pd.to_numeric(self.trades['result'], errors='coerce').fillna(1.0)
|
|
54
|
+
days = pd.to_numeric(self.trades['days_in_trade'], errors='coerce').fillna(0)
|
|
55
|
+
|
|
56
|
+
n_trades = len(self.trades)
|
|
57
|
+
win_trades = results[results > 1]
|
|
58
|
+
loss_trades = results[results < 1]
|
|
59
|
+
|
|
60
|
+
# Calculate profit percentages
|
|
61
|
+
profit_pcts = (results - 1) * 100
|
|
62
|
+
win_profit_pcts = profit_pcts[results > 1]
|
|
63
|
+
loss_profit_pcts = profit_pcts[results < 1]
|
|
64
|
+
|
|
65
|
+
# Basic metrics
|
|
66
|
+
win_ratio = (len(win_trades) / n_trades) * 100 if n_trades > 0 else 0
|
|
67
|
+
avg_res = profit_pcts.mean()
|
|
68
|
+
median_res = profit_pcts.median()
|
|
69
|
+
cum_res = results.prod()
|
|
70
|
+
|
|
71
|
+
# Detailed profit/loss metrics
|
|
72
|
+
profitable_trades_mean = win_profit_pcts.mean() if len(win_profit_pcts) > 0 else 0
|
|
73
|
+
profitable_trades_median = win_profit_pcts.median() if len(win_profit_pcts) > 0 else 0
|
|
74
|
+
looser_trades_mean = loss_profit_pcts.mean() if len(loss_profit_pcts) > 0 else 0
|
|
75
|
+
looser_trades_median = loss_profit_pcts.median() if len(loss_profit_pcts) > 0 else 0
|
|
76
|
+
|
|
77
|
+
# Trade results lists
|
|
78
|
+
trade_results_str = " # ".join([f"{x:.2f}" for x in profit_pcts.values[:10]]) # First 10
|
|
79
|
+
if len(profit_pcts) > 10:
|
|
80
|
+
trade_results_str += " # ..."
|
|
81
|
+
|
|
82
|
+
profitable_results_str = " # ".join([f"{x:.2f}" for x in win_profit_pcts.values[:10]])
|
|
83
|
+
if len(win_profit_pcts) > 10:
|
|
84
|
+
profitable_results_str += " # ..."
|
|
85
|
+
|
|
86
|
+
looser_results_str = " # ".join([f"{x:.2f}" for x in loss_profit_pcts.values[:10]])
|
|
87
|
+
if len(loss_profit_pcts) > 10:
|
|
88
|
+
looser_results_str += " # ..."
|
|
89
|
+
|
|
90
|
+
# Date and price info
|
|
91
|
+
first_trade_date = self.trades['buy_date'].iloc[0] if 'buy_date' in self.trades.columns else None
|
|
92
|
+
last_trade_date = self.trades['sell_date'].iloc[-1] if 'sell_date' in self.trades.columns else None
|
|
93
|
+
first_data_date = self.data['date'].iloc[0]
|
|
94
|
+
last_data_date = self.data['date'].iloc[-1]
|
|
95
|
+
first_open_price = self.data['open'].iloc[0]
|
|
96
|
+
last_close_price = self.data['close'].iloc[-1]
|
|
97
|
+
|
|
98
|
+
# Hold result
|
|
99
|
+
hold_result = last_close_price / first_open_price
|
|
100
|
+
|
|
101
|
+
# Buy/Sell colors (from original strategy if available)
|
|
102
|
+
buy_color = self.additional_params.get('buy_at', 'gold')
|
|
103
|
+
sell_color = self.additional_params.get('sell_at', 'grey')
|
|
104
|
+
|
|
105
|
+
self.trades_summary = {
|
|
106
|
+
'ticker': self.data['ticker'].iloc[0] if 'ticker' in self.data.columns else 'Unknown',
|
|
107
|
+
'number_of_trades': n_trades,
|
|
108
|
+
'win_ratio(%)': round(win_ratio, 2),
|
|
109
|
+
'average_res(%)': round(avg_res, 2),
|
|
110
|
+
'average_trade_len(days)': round(days.mean(), 1),
|
|
111
|
+
'median_res(%)': round(median_res, 2),
|
|
112
|
+
'cumulative_result': round(cum_res, 6),
|
|
113
|
+
'trade_results': trade_results_str,
|
|
114
|
+
'profitable_trade_results': profitable_results_str,
|
|
115
|
+
'profitable_trades_mean': round(profitable_trades_mean, 2),
|
|
116
|
+
'profitable_trades_median': round(profitable_trades_median, 2),
|
|
117
|
+
'looser_trade_results': looser_results_str,
|
|
118
|
+
'looser_trades_mean': round(looser_trades_mean, 2),
|
|
119
|
+
'looser_trades_median': round(looser_trades_median, 2),
|
|
120
|
+
'median_trade_len(days)': round(days.median(), 1),
|
|
121
|
+
'number_of_win_trades': len(win_trades),
|
|
122
|
+
'number_of_lost_trades': len(loss_trades),
|
|
123
|
+
'max_gain(%)': round((results.max() - 1) * 100, 2),
|
|
124
|
+
'max_lost(%)': round((results.min() - 1) * 100, 2),
|
|
125
|
+
'first_trade_buy': str(first_trade_date) if first_trade_date else 'N/A',
|
|
126
|
+
'first_data_date': str(first_data_date),
|
|
127
|
+
'first_open_price': round(first_open_price, 6),
|
|
128
|
+
'last_data_date': str(last_data_date),
|
|
129
|
+
'last_close_price': round(last_close_price, 6),
|
|
130
|
+
'hold_result': f"{round(hold_result, 2)} x",
|
|
131
|
+
'buy_at': buy_color,
|
|
132
|
+
'sell_at': sell_color
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
# Add additional params to summary for context
|
|
136
|
+
self.trades_summary.update(self.additional_params)
|
|
137
|
+
|
|
138
|
+
# Format text for plot
|
|
139
|
+
self.trade_summary_plot_text = (
|
|
140
|
+
f"Trades: {self.trades_summary['number_of_trades']}<br>"
|
|
141
|
+
f"Win ratio: {self.trades_summary['win_ratio(%)']}%<br>"
|
|
142
|
+
f"Avg Result: {self.trades_summary['average_res(%)']}%<br>"
|
|
143
|
+
f"Cum Result: {self.trades_summary['cumulative_result']}<br>"
|
|
144
|
+
f"Hold Result: {self.trades_summary['hold_result']}"
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
def show_trades(self):
|
|
148
|
+
"""
|
|
149
|
+
Return the plotly figure with trades.
|
|
150
|
+
"""
|
|
151
|
+
if self.trades.empty:
|
|
152
|
+
print("No trades to show.")
|
|
153
|
+
return Plotting._create_base_ohlc(self.data)
|
|
154
|
+
|
|
155
|
+
return Plotting.plot_strategy_trades(
|
|
156
|
+
self.data,
|
|
157
|
+
self.trades,
|
|
158
|
+
title=self.plot_title,
|
|
159
|
+
summary_text=self.trade_summary_plot_text
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
def summarize_strategy(self):
|
|
163
|
+
"""
|
|
164
|
+
Display summary table and plot.
|
|
165
|
+
"""
|
|
166
|
+
display(pd.DataFrame(self.trades_summary, index=['Strategy summary']).T)
|
|
167
|
+
self.show_trades().show()
|
|
168
|
+
display(self.trades)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import yfinance as yf
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from datetime import datetime, timedelta
|
|
4
|
+
|
|
5
|
+
class Data:
|
|
6
|
+
"""
|
|
7
|
+
Class to handle data downloading from Yahoo Finance.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
@staticmethod
|
|
11
|
+
def download(ticker: str, period: str = 'max', interval: str = '1d', auto_adjust: bool = True) -> pd.DataFrame:
|
|
12
|
+
"""
|
|
13
|
+
Download historical data for a single ticker.
|
|
14
|
+
|
|
15
|
+
Parameters:
|
|
16
|
+
- ticker: str, symbol (e.g., 'AAPL', 'BTC-USD')
|
|
17
|
+
- period: str, data period to download (e.g. '1y', '2y', 'max')
|
|
18
|
+
- interval: str, data interval (e.g. '1d', '1h')
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
- pd.DataFrame with lowercase columns ['date', 'open', 'high', 'low', 'close', 'volume', 'ticker']
|
|
22
|
+
"""
|
|
23
|
+
try:
|
|
24
|
+
# Using yfinance to download data
|
|
25
|
+
# auto_adjust=True fixes the Close price for splits and dividends
|
|
26
|
+
df = yf.download(ticker, period=period, interval=interval, auto_adjust=auto_adjust, progress=False, multi_level_index=False)
|
|
27
|
+
|
|
28
|
+
if df.empty:
|
|
29
|
+
print(f"Warning: No data found for ticker {ticker}")
|
|
30
|
+
return pd.DataFrame()
|
|
31
|
+
|
|
32
|
+
# Clean up DataFrame
|
|
33
|
+
df.reset_index(inplace=True)
|
|
34
|
+
df.columns = df.columns.str.lower()
|
|
35
|
+
|
|
36
|
+
# Rename 'Date'/'Datetime' to 'date' consistently
|
|
37
|
+
if 'date' not in df.columns:
|
|
38
|
+
if 'datetime' in df.columns:
|
|
39
|
+
df.rename(columns={'datetime': 'date'}, inplace=True)
|
|
40
|
+
|
|
41
|
+
# Ensure 'date' column is datetime.date objects for compatibility with existing logic
|
|
42
|
+
if 'date' in df.columns:
|
|
43
|
+
df['date'] = pd.to_datetime(df['date']).dt.date
|
|
44
|
+
|
|
45
|
+
# Add ticker column
|
|
46
|
+
df['ticker'] = ticker
|
|
47
|
+
|
|
48
|
+
# Select relevant columns
|
|
49
|
+
cols = ['date', 'open', 'high', 'low', 'close', 'volume', 'ticker']
|
|
50
|
+
df = df[[c for c in cols if c in df.columns]]
|
|
51
|
+
|
|
52
|
+
return df
|
|
53
|
+
|
|
54
|
+
except Exception as e:
|
|
55
|
+
print(f"Error downloading data for {ticker}: {e}")
|
|
56
|
+
return pd.DataFrame()
|
|
57
|
+
|
|
58
|
+
@staticmethod
|
|
59
|
+
def get_ticker_info(ticker: str) -> dict:
|
|
60
|
+
"""
|
|
61
|
+
Get fundamental info about the ticker.
|
|
62
|
+
"""
|
|
63
|
+
try:
|
|
64
|
+
t = yf.Ticker(ticker)
|
|
65
|
+
return t.info
|
|
66
|
+
except Exception as e:
|
|
67
|
+
print(f"Error getting info for {ticker}: {e}")
|
|
68
|
+
return {}
|