Skip to content

Commit a50ffd3

Browse files
Add DUAL_THRUST
1 parent 89ba99a commit a50ffd3

File tree

2 files changed

+263
-0
lines changed

2 files changed

+263
-0
lines changed

.gitignore

+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# C extensions
7+
*.so
8+
9+
# Distribution / packaging
10+
.Python
11+
build/
12+
develop-eggs/
13+
dist/
14+
downloads/
15+
eggs/
16+
.eggs/
17+
lib/
18+
lib64/
19+
parts/
20+
sdist/
21+
var/
22+
wheels/
23+
share/python-wheels/
24+
*.egg-info/
25+
.installed.cfg
26+
*.egg
27+
MANIFEST
28+
29+
# PyInstaller
30+
# Usually these files are written by a python script from a template
31+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
32+
*.manifest
33+
*.spec
34+
35+
# Installer logs
36+
pip-log.txt
37+
pip-delete-this-directory.txt
38+
39+
# Unit test / coverage reports
40+
htmlcov/
41+
.tox/
42+
.nox/
43+
.coverage
44+
.coverage.*
45+
.cache
46+
nosetests.xml
47+
coverage.xml
48+
*.cover
49+
*.py,cover
50+
.hypothesis/
51+
.pytest_cache/
52+
cover/
53+
54+
# Translations
55+
*.mo
56+
*.pot
57+
58+
# Django stuff:
59+
*.log
60+
local_settings.py
61+
db.sqlite3
62+
db.sqlite3-journal
63+
64+
# Flask stuff:
65+
instance/
66+
.webassets-cache
67+
68+
# Scrapy stuff:
69+
.scrapy
70+
71+
# Sphinx documentation
72+
docs/_build/
73+
74+
# PyBuilder
75+
.pybuilder/
76+
target/
77+
78+
# Jupyter Notebook
79+
.ipynb_checkpoints
80+
81+
# IPython
82+
profile_default/
83+
ipython_config.py
84+
85+
# pyenv
86+
# For a library or package, you might want to ignore these files since the code is
87+
# intended to run in multiple environments; otherwise, check them in:
88+
# .python-version
89+
90+
# pipenv
91+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
93+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
94+
# install all needed dependencies.
95+
#Pipfile.lock
96+
97+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
98+
__pypackages__/
99+
100+
# Celery stuff
101+
celerybeat-schedule
102+
celerybeat.pid
103+
104+
# SageMath parsed files
105+
*.sage.py
106+
107+
# Environments
108+
.env
109+
.venv
110+
env/
111+
venv/
112+
ENV/
113+
env.bak/
114+
venv.bak/
115+
116+
# Spyder project settings
117+
.spyderproject
118+
.spyproject
119+
120+
# Rope project settings
121+
.ropeproject
122+
123+
# mkdocs documentation
124+
/site
125+
126+
# mypy
127+
.mypy_cache/
128+
.dmypy.json
129+
dmypy.json
130+
131+
# Pyre type checker
132+
.pyre/
133+
134+
# pytype static type analyzer
135+
.pytype/
136+
137+
# Cython debug symbols
138+
cython_debug/
139+
140+
# IDE
141+
/.vscode
142+
/.idea
143+
144+
.DS_Store
145+
/storage/*.key
146+
/storage/*.sqlite
147+
/storage/*.gz
148+
/.vagrant
149+
testing-*.py
150+
/storage/full-reports/*.html
151+
/storage/logs/*

DUAL_THRUST/__init__.py

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
from jesse.strategies import Strategy, cached
2+
import jesse.indicators as ta
3+
from jesse import utils
4+
import numpy as np
5+
6+
# https://medium.com/@gaea.enquiries/quantitative-strategy-research-series-one-the-dual-thrust-38380b38c2fa
7+
# Dual Thrust by Michael Chalek
8+
9+
class DUAL_THRUST(Strategy):
10+
11+
def should_long(self) -> bool:
12+
return self.long_cond
13+
14+
def should_short(self) -> bool:
15+
return self.short_cond
16+
17+
def go_long(self):
18+
entry = self.price
19+
stop = entry - self.atr * self.hp['stop_loss_atr_rate']
20+
qty = utils.risk_to_qty(self.capital, 2, entry, stop)
21+
self.buy = qty, entry
22+
self.stop_loss = qty, stop
23+
24+
def go_short(self):
25+
entry = self.price
26+
stop = entry + self.atr * self.hp['stop_loss_atr_rate']
27+
qty = utils.risk_to_qty(self.capital, 2, entry, stop)
28+
self.sell = qty, entry
29+
self.stop_loss = qty, stop
30+
31+
def update_position(self):
32+
if (self.is_long and self.short_cond) or (self.is_short and self.long_cond):
33+
self.liquidate()
34+
35+
def should_cancel(self) -> bool:
36+
return True
37+
38+
################################################################
39+
# # # # # # # # # # # # # indicators # # # # # # # # # # # # # #
40+
################################################################
41+
42+
@property
43+
def up_min_low(self):
44+
return np.min(self.candles[:, 4][-self.hp['up_length']:])
45+
46+
@property
47+
def up_min_close(self):
48+
return np.min(self.candles[:, 2][-self.hp['up_length']:])
49+
50+
@property
51+
def up_max_close(self):
52+
return np.max(self.candles[:, 2][-self.hp['up_length']:])
53+
54+
@property
55+
def up_max_high(self):
56+
return np.max(self.candles[:, 3][-self.hp['up_length']:])
57+
58+
@property
59+
def down_min_low(self):
60+
return np.min(self.candles[:, 4][-self.hp['down_length']:])
61+
62+
@property
63+
def down_min_close(self):
64+
return np.min(self.candles[:, 2][-self.hp['down_length']:])
65+
66+
@property
67+
def down_max_close(self):
68+
return np.max(self.candles[:, 2][-self.hp['down_length']:])
69+
70+
@property
71+
def down_max_high(self):
72+
return np.max(self.candles[:, 4][-self.hp['down_length']:])
73+
74+
@property
75+
def up_thurst(self):
76+
return self.anchor_candles[:, 1][-1] + self.hp['up_coeff'] * max(self.up_max_close - self.up_min_low, self.up_max_high - self.up_min_close)
77+
78+
@property
79+
def down_thrust(self):
80+
return self.anchor_candles[:, 1][-1] - self.hp['down_coeff'] * max(self.down_max_close - self.down_min_low, self.down_max_high - self.down_min_close)
81+
82+
@property
83+
@cached
84+
def anchor_candles(self):
85+
return self.get_candles(self.exchange, self.symbol, utils.anchor_timeframe(self.timeframe))
86+
87+
@property
88+
def short_cond(self):
89+
return self.price < self.down_thrust
90+
91+
@property
92+
def long_cond(self):
93+
return self.price > self.up_thurst
94+
95+
@property
96+
def atr(self):
97+
return ta.atr(self.candles)
98+
99+
100+
# # # # # # # # # # # # # # # # # # # # # # # # # # # #
101+
# Genetic
102+
# # # # # # # # # # # # # # # # # # # # # # # # # # # #
103+
104+
def hyperparameters(self):
105+
return [
106+
{'name': 'stop_loss_atr_rate', 'type': float, 'min': 0.1, 'max': 2.0, 'default': 2},
107+
{'name': 'down_length', 'type': int, 'min': 3, 'max': 30, 'default': 21},
108+
{'name': 'up_length', 'type': int, 'min': 3, 'max': 30, 'default': 21},
109+
{'name': 'down_coeff', 'type': float, 'min': 0.1, 'max': 3.0, 'default': 0.67},
110+
{'name': 'up_coeff', 'type': float, 'min': 0.1, 'max': 3.0, 'default': 0.71},
111+
]
112+

0 commit comments

Comments
 (0)