1146 Commits

Author SHA1 Message Date
Saleh Mir
92269df6b8 refactor order execution and event firing 2022-03-03 08:51:54 +01:00
Saleh Mir
25f1076629 refactor handling of CompletedTrade models and how orders affect positions 2022-02-28 10:56:49 +01:00
Saleh Mir
2f45ddfca5 handle exchange balances via WS 2022-02-24 11:34:01 +01:00
Saleh Mir
bafb17684d modify api text for liquidation_price of the dashboard 2022-02-23 19:01:46 +01:00
Saleh Mir
5b42f88531 handle positions stream in live-trade 2022-02-23 18:14:28 +01:00
Saleh Mir
1a3f76a38e bring back simplejson 2022-02-22 15:19:54 +01:00
Saleh Mir
6e5daa90ff lock dependencies 2022-02-22 14:53:59 +01:00
Saleh Mir
0f2b07a553 use jimplejson instead 2022-02-22 14:53:31 +01:00
Saleh Mir
b2ebd2d5c5 Merge pull request #317 from jcsaaddupuy/feat/redis_support_multidb
supports custom redis database number by passing REDIS_DB throught environment
2022-02-21 15:44:05 +01:00
Saleh Mir
a704fbe13e Merge pull request #323 from jesse-ai/dependabot/pip/numpy-1.22.2
Bump numpy from 1.22.1 to 1.22.2
2022-02-21 15:41:28 +01:00
Saleh Mir
f95420082b Merge branch 'master' into dependabot/pip/numpy-1.22.2 2022-02-21 15:41:23 +01:00
Saleh Mir
4ff679e987 Merge pull request #322 from jesse-ai/dependabot/pip/scipy-1.8.0
Bump scipy from 1.7.3 to 1.8.0
2022-02-21 15:40:47 +01:00
dependabot[bot]
04f1f01f3b Bump scipy from 1.7.3 to 1.8.0
Bumps [scipy](https://github.com/scipy/scipy) from 1.7.3 to 1.8.0.
- [Release notes](https://github.com/scipy/scipy/releases)
- [Commits](https://github.com/scipy/scipy/compare/v1.7.3...v1.8.0)

---
updated-dependencies:
- dependency-name: scipy
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-21 14:40:40 +00:00
dependabot[bot]
7d39502faf Bump numpy from 1.22.1 to 1.22.2
Bumps [numpy](https://github.com/numpy/numpy) from 1.22.1 to 1.22.2.
- [Release notes](https://github.com/numpy/numpy/releases)
- [Changelog](https://github.com/numpy/numpy/blob/main/doc/HOWTO_RELEASE.rst.txt)
- [Commits](https://github.com/numpy/numpy/compare/v1.22.1...v1.22.2)

---
updated-dependencies:
- dependency-name: numpy
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-21 14:40:12 +00:00
Saleh Mir
bd1e644e06 Merge pull request #319 from jesse-ai/dependabot/pip/redis-4.1.4
Bump redis from 3.5.3 to 4.1.4
2022-02-21 15:40:04 +01:00
dependabot[bot]
ccb6d641f1 Bump redis from 3.5.3 to 4.1.4
Bumps [redis](https://github.com/redis/redis-py) from 3.5.3 to 4.1.4.
- [Release notes](https://github.com/redis/redis-py/releases)
- [Changelog](https://github.com/redis/redis-py/blob/master/CHANGES)
- [Commits](https://github.com/redis/redis-py/compare/3.5.3...v4.1.4)

---
updated-dependencies:
- dependency-name: redis
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-21 14:39:40 +00:00
Saleh Mir
515e069d6c Merge pull request #320 from jesse-ai/dependabot/pip/fastapi-0.74.0
Bump fastapi from 0.65.2 to 0.74.0
2022-02-21 15:39:05 +01:00
Saleh Mir
c2503e4e8e bump verion 2022-02-21 10:20:54 +01:00
Saleh Mir
9d95c82982 implement order.is_stop_loss and order.is_take_profit properties 2022-02-21 10:20:49 +01:00
Saleh Mir
94460749cc fix tests 2022-02-21 10:06:03 +01:00
dependabot[bot]
493e5d9e41 Bump fastapi from 0.65.2 to 0.74.0
Bumps [fastapi](https://github.com/tiangolo/fastapi) from 0.65.2 to 0.74.0.
- [Release notes](https://github.com/tiangolo/fastapi/releases)
- [Commits](https://github.com/tiangolo/fastapi/compare/0.65.2...0.74.0)

---
updated-dependencies:
- dependency-name: fastapi
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-17 23:28:14 +00:00
Saleh Mir
18da8c87b7 bump version 2022-02-16 04:18:43 +01:00
Saleh Mir
8da9b0818e round position value by 2 decimals 2022-02-15 10:29:35 +01:00
Saleh Mir
91ffb61d2d update frontend 2022-02-15 09:49:26 +01:00
Saleh Mir
cfe28d677d log the traceback of the exception 2022-02-15 09:47:24 +01:00
Saleh Mir
fe74aadc15 Revert "Sourcery (#316)"
This reverts commit cff9e69446.
2022-02-14 13:56:57 +01:00
Saleh Mir
46e4ef5557 Merge branch 'master' of github.com:jesse-ai/jesse 2022-02-14 13:53:06 +01:00
Saleh Mir
2a4de527d3 send value and currency of the position 2022-02-14 13:53:02 +01:00
Saleh Mir
2d67f5f46f fix for watch list 2022-02-14 09:59:29 +01:00
jcsaaddupuy
074b91f633 supports custom redis database number by passing REDIS_DB to env 2022-02-12 00:44:55 +01:00
Markus K
cff9e69446 Sourcery (#316)
* Sourcery

* Fix failure

* Refactor
2022-02-11 17:34:40 +01:00
Saleh Mir
e3b5cef2c4 update sponsor link 2022-02-11 08:43:26 +01:00
Saleh Mir
43f260d564 bump version 2022-02-10 17:43:24 +01:00
Saleh Mir
4f8f08f04d add sponsored promotion 2022-02-10 17:43:03 +01:00
Saleh Mir
7201e9c483 update frontend 2022-02-10 17:03:00 +01:00
Saleh Mir
b2a9191b30 add support for all types to watch_list + improve error 2022-02-10 08:39:12 +01:00
Saleh Mir
deae30482c add support for bool_ values in watch_list() 2022-02-10 08:04:36 +01:00
Saleh Mir
f9592183cd update frontend + bump version 2022-02-09 21:36:12 +01:00
Saleh Mir
2f9a9235db bump version 2022-02-09 17:28:42 +01:00
Saleh Mir
5d89a48193 remove debugging code 2022-02-09 17:28:23 +01:00
Saleh Mir
cd7c41a2e0 fix + improve optimize's debugging mode 2022-02-09 17:28:12 +01:00
Saleh Mir
b75f1e87b5 implement clear_file() helper function 2022-02-09 10:44:28 +01:00
Saleh Mir
443c2c58fb bump version 2022-02-07 11:43:47 +01:00
Saleh Mir
accbec8d2b update frontend files 2022-02-07 11:43:31 +01:00
Saleh Mir
d0cec7f964 bump version 2022-02-07 08:14:42 +01:00
Saleh Mir
b9472b86b5 add support for multiple instances running simultaneously 2022-02-07 08:12:42 +01:00
Saleh Mir
1d894d40e7 Update test_helpers.py 2022-02-07 08:12:06 +01:00
Markus K
da16d68fd3 Update backtest.py 2022-02-06 13:04:56 +01:00
Markus K
42c8028ba9 Pass hyperparameters again. 2022-02-06 12:57:42 +01:00
Saleh Mir
6299fdca96 make should_short and go_short optional 2022-02-06 08:54:17 +01:00
Saleh Mir
d7cf800122 update frontend files 2022-02-05 17:14:30 +01:00
Saleh Mir
2e3b74b497 bump version 2022-02-05 17:11:51 +01:00
Saleh Mir
8a3d1744da fix extra-routes in optimize mode 2022-02-05 17:10:26 +01:00
Saleh Mir
9b3354ea4b bump version 2022-02-04 18:08:37 +01:00
Saleh Mir
0b339ce99e allow for longer symbols + fix symbol issue with uppercase 2022-02-04 18:08:18 +01:00
Saleh Mir
659e31fc6e fix version 2022-02-02 16:41:20 +01:00
Saleh Mir
33068dd814 bump version 2022-02-01 17:10:26 +01:00
Saleh Mir
1d39872116 Merge branch 'master' of github.com:jesse-ai/jesse 2022-02-01 16:22:51 +01:00
Saleh Mir
dabd624d8e fix the issue of margin in timestamp of candles on the live dashboard 2022-02-01 16:22:46 +01:00
Markus K
f858447bd7 Update Optimize.py 2022-02-01 14:51:43 +01:00
Markus K
4e3f3fd679 Update Optimize.py 2022-02-01 14:51:03 +01:00
Saleh Mir
7a78c606a7 fix tests 2022-02-01 14:41:31 +01:00
Saleh Mir
75c0416dc9 Strategy execution for update_position is paused for 3 seconds if an order execution event was received before update_position was called 2022-02-01 09:40:21 +01:00
Saleh Mir
01ddba050a update frontend 2022-01-31 10:10:31 +01:00
Saleh Mir
d57d8226af Merge branch 'master' of github.com:jesse-ai/jesse 2022-01-31 10:04:44 +01:00
Saleh Mir
892bb78a7a Merge pull request #307 from botzill/update-pg-envs
Add new env POSTGRES_SSLMODE
2022-01-30 08:42:17 +01:00
Chirica Gheorghe
683afc24e7 Add new env POSTGRES_SSLMODE 2022-01-27 20:24:02 +02:00
Saleh Mir
55270a232d display hyperparameters after backtests 2022-01-27 16:47:42 +01:00
Saleh Mir
8148a7d88b update report.watch_list() 2022-01-27 16:06:44 +01:00
Saleh Mir
e96aa74112 bump version 2022-01-26 18:32:55 +01:00
Saleh Mir
9470d9758a send a simple error warning when using more than 5 trading routes in live modes 2022-01-26 18:32:26 +01:00
Saleh Mir
02830c5b1d improve termination message for strategies 2022-01-26 17:49:42 +01:00
Saleh Mir
4deaa03466 fix typo 2022-01-26 17:49:26 +01:00
Saleh Mir
8931d7ab0c store candles and logs synchronously into DB instead 2022-01-26 15:45:04 +01:00
Markus K
1300b0983d Update ta-lib cache 2022-01-26 10:12:10 +01:00
Markus K
26d8ddaa9d Update requirements for C header error 2022-01-26 10:04:40 +01:00
Saleh Mir
6e1fb66bf8 refactor 2022-01-25 17:02:12 +01:00
Saleh Mir
4b30a0daee add candles_from_close_prices, fake_candle, fake_range_candles, candlestick_chart to the research module 2022-01-25 17:02:05 +01:00
Saleh Mir
b707a145d2 update info() logger 2022-01-24 08:45:32 +01:00
Saleh Mir
d9f383cb74 add unit tests for isolated backtest() 2022-01-21 16:14:11 +01:00
Saleh Mir
cf24917508 implement isolated backtest function for the research module 2022-01-21 15:05:42 +01:00
Saleh Mir
fb40bbd46e create basic testing env for isolated backtest 2022-01-21 15:00:34 +01:00
Saleh Mir
b3a67bb0bf refactor 2022-01-21 15:00:19 +01:00
Saleh Mir
c1c8eef2f2 cleanup + fix rare KeyError in chart generation 2022-01-21 14:59:03 +01:00
Saleh Mir
2b5a0c5a61 do not log fee charging if fee==0 2022-01-21 14:56:41 +01:00
Saleh Mir
646de628fd bump version 2022-01-17 16:41:03 +01:00
Saleh Mir
5040104114 add to_dict property to the Position class 2022-01-17 15:29:00 +01:00
Saleh Mir
47783b1f70 error logs should be logged as info logs as well 2022-01-17 15:27:41 +01:00
Saleh Mir
6f45550a26 rename positions => all_positions 2022-01-16 09:29:36 +01:00
Saleh Mir
57199568e9 update comment text 2022-01-16 09:29:24 +01:00
Saleh Mir
cdb222b203 refactor directory 2022-01-14 16:42:40 +01:00
Saleh Mir
9fede6adae rename fake_range_candle => range_candles and fake_range_candle_from_range_prices => candles_from_close_prices 2022-01-14 11:59:42 +01:00
Saleh Mir
8e3a255926 start fake candles from 2021-01-01T00:00 2022-01-14 11:36:49 +01:00
Saleh Mir
697cf51827 convert non-string inputs into string first 2022-01-13 15:42:56 +01:00
Saleh Mir
2875954713 fix and error when handling rejected orders 2022-01-13 11:07:02 +01:00
Saleh Mir
905f53c884 update frontend files 2022-01-13 09:51:26 +01:00
Saleh Mir
95ca0d5c96 bump version 2022-01-12 14:47:34 +01:00
Saleh Mir
57032a5069 fix Discord notifications 2022-01-12 14:47:12 +01:00
Saleh Mir
96c11a6b12 Merge branch 'master' of github.com:jesse-ai/jesse 2022-01-12 14:31:38 +01:00
Saleh Mir
f782a40de3 improve handling of take_profit and stop_loss on open-position event 2022-01-12 14:31:33 +01:00
Saleh Mir
4bb7c3e1cd add dashy_symbol() and improve side_to_type() 2022-01-12 14:31:00 +01:00
Markus K
dd9ecfb312 Clear cache due to numpy.ndarray size changed 2022-01-07 14:12:58 +01:00
Markus K
be065c56c3 Clear cache due to numpy.ndarray size changed 2022-01-07 14:12:19 +01:00
Saleh Mir
611023fec7 Merge pull request #286 from poe28/master
tool for showing candle DB overview
2022-01-07 10:46:40 +01:00
Saleh Mir
edae58368b send useful debugging info in exception reports 2022-01-07 10:19:06 +01:00
Saleh Mir
34a4cf456d bump version 2022-01-07 09:52:30 +01:00
Saleh Mir
fc25d48ccc add support for cancelling entry orders in update_position() 2022-01-07 09:46:21 +01:00
Saleh Mir
b8a1f131f3 rename _open_position_orders => _entry_orders and _close_position_orders => _exit_orders 2022-01-06 15:33:08 +01:00
Saleh Mir
704acb01b2 fix an issue in updating _open_position_orders 2022-01-06 15:31:35 +01:00
Saleh Mir
cb2a01424a update frontend files 2022-01-05 15:47:12 +01:00
Saleh Mir
91b6875ed7 add is_docker to general-info 2022-01-05 15:47:05 +01:00
Markus
30d4eb08e2 Catch EOFError in Cache 2021-12-30 18:42:50 +01:00
Saleh Mir
8629922e0b add positions and portfolio_value properties to the Strategy class 2021-12-30 17:45:49 +01:00
Saleh Mir
832e1f5d00 bump version 2021-12-27 17:04:19 +01:00
Saleh Mir
50e62ee53c update frontend files 2021-12-27 17:04:02 +01:00
Saleh Mir
a0d9a7bfae add "system_info" to the general-info endpoint 2021-12-27 17:03:56 +01:00
Saleh Mir
4198892e91 add get_os() helper 2021-12-27 17:03:39 +01:00
Saleh Mir
29f015a46a bump version 2021-12-27 15:05:58 +01:00
Saleh Mir
c8bf332636 fix strategy init bug on live trade 2021-12-27 15:05:37 +01:00
Saleh Mir
65c3c2c621 fix migrations 2021-12-27 10:47:57 +01:00
Saleh Mir
ed8ccc2a5d bump version 2021-12-26 16:30:46 +01:00
Saleh Mir
6a6dcecd84 bump version 2021-12-26 16:09:36 +01:00
Saleh Mir
a88aa0f1bd bring back support for using Jesse in Jupyter notebooks 2021-12-26 16:09:28 +01:00
Saleh Mir
a6cdf0cdfe add is_notebook() helper 2021-12-26 16:09:21 +01:00
Saleh Mir
bc78dbe014 bump version 2021-12-24 16:33:49 +01:00
Saleh Mir
2194271eaf update frontend files 2021-12-24 16:33:00 +01:00
Saleh Mir
481f5730bc fix a bug for live-trade when using extra-routes 2021-12-24 10:11:09 +01:00
Markus K
0f3d6015a5 Missing talib directory. 2021-12-22 11:15:06 +01:00
Markus K
d7abeec624 Fix permission.
uses: john-shaffer/cache@sudo-tar
2021-12-22 11:08:27 +01:00
Markus K
fc8c76fa06 fix ta-lib directory. 2021-12-21 11:38:08 +01:00
Markus K
fcfbbfdf36 Only talib files 2021-12-21 11:29:02 +01:00
Markus K
bf9a55ea16 Move if. 2021-12-21 11:15:22 +01:00
Markus K
f99682c153 Fix cache condition - workflow 2021-12-21 11:06:58 +01:00
Markus K
dfcadd9c7c Cache talib - workflow 2021-12-21 11:02:35 +01:00
Markus K
93d6f4040e Revert. 2021-12-20 11:42:58 +01:00
Markus K
55dbf55cfe Fix 2021-12-20 11:41:05 +01:00
Markus K
ce9b2bcb70 New cache. 2021-12-20 11:32:33 +01:00
Markus K
bf5f75149b Fix 2021-12-20 11:29:20 +01:00
Markus K
037e3784f6 Update cache. 2021-12-20 11:26:19 +01:00
Markus K
47ac3015a6 Revert and try to check for cache. 2021-12-20 11:22:30 +01:00
Markus K
b0bebba533 Use talib-binary for faster tests. 2021-12-20 11:09:22 +01:00
Markus K
ec3f30f649 Drop 3.7 2021-12-20 11:08:10 +01:00
Saleh Mir
efab55f69f fix. the python-version format for installer 2021-12-20 10:36:12 +01:00
Saleh Mir
7c1fb25539 fix versions 2021-12-20 10:30:00 +01:00
Saleh Mir
cfee29d71b fix the issue of static files not being included in the package 2021-12-20 09:47:38 +01:00
Saleh Mir
add50137e4 bump version 2021-12-20 09:13:32 +01:00
Saleh Mir
a4607e6532 make requirements less strict again 2021-12-20 09:13:21 +01:00
Saleh Mir
9800e0cf80 fix syntax typo 2021-12-20 07:44:38 +01:00
Saleh Mir
044b7cae26 pass jesse_version for install-live command 2021-12-20 07:43:05 +01:00
Saleh Mir
0cbf910f6a fix version 2021-12-20 07:26:54 +01:00
Saleh Mir
44b88fb555 bring back the old readme file 2021-12-19 15:32:54 +01:00
Saleh Mir
f42f2b482d update info links 2021-12-19 15:31:48 +01:00
Saleh Mir
8d977276c2 Merge branch 'dashboard' 2021-12-19 15:30:38 +01:00
Saleh Mir
1dbec2f2a8 bump version 2021-12-19 15:25:30 +01:00
Saleh Mir
fb912b8580 update frontend files 2021-12-17 09:16:37 +01:00
Saleh Mir
846707fd4a Merge branch 'dashboard' of github.com:jesse-ai/jesse into dashboard 2021-12-17 09:14:12 +01:00
Saleh Mir
895f3e76c3 add email to feedback and exception report forms 2021-12-17 09:14:08 +01:00
Markus
7164d84f93 Fix hurst numba guvectorize error. 2021-12-16 11:13:31 +01:00
Markus
ffdf6e21bb Merge remote-tracking branch 'origin/dashboard' into dashboard 2021-12-16 11:11:32 +01:00
Markus
3cdfb8d730 Load install_requires from "requirements.txt". 2021-12-16 11:10:49 +01:00
Markus
aef34d77c1 Load install_requires from "requirements.txt". 2021-12-16 11:10:05 +01:00
dependabot[bot]
bfec5ffcfb Bump mplfinance from 0.12.8b4 to 0.12.8b6 (#291)
Bumps [mplfinance](https://github.com/matplotlib/mplfinance) from 0.12.8b4 to 0.12.8b6.
- [Release notes](https://github.com/matplotlib/mplfinance/releases)
- [Changelog](https://github.com/matplotlib/mplfinance/blob/master/RELEASE_NOTES.md)
- [Commits](https://github.com/matplotlib/mplfinance/compare/v0.12.8b4...v0.12.8b6)

---
updated-dependencies:
- dependency-name: mplfinance
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-12-16 10:51:34 +01:00
dependabot[bot]
f639a46a78 Bump mplfinance from 0.12.7a17 to 0.12.8b4 (#290)
Bumps [mplfinance](https://github.com/matplotlib/mplfinance) from 0.12.7a17 to 0.12.8b4.
- [Release notes](https://github.com/matplotlib/mplfinance/releases)
- [Changelog](https://github.com/matplotlib/mplfinance/blob/master/RELEASE_NOTES.md)
- [Commits](https://github.com/matplotlib/mplfinance/commits/v0.12.8b4)

---
updated-dependencies:
- dependency-name: mplfinance
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-12-15 14:33:33 +01:00
dependabot[bot]
cea30d918e Bump matplotlib from 3.5.0 to 3.5.1 (#289)
Bumps [matplotlib](https://github.com/matplotlib/matplotlib) from 3.5.0 to 3.5.1.
- [Release notes](https://github.com/matplotlib/matplotlib/releases)
- [Commits](https://github.com/matplotlib/matplotlib/compare/v3.5.0...v3.5.1)

---
updated-dependencies:
- dependency-name: matplotlib
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-12-14 13:50:07 +01:00
dependabot[bot]
075a97c8e2 Bump pandas from 1.3.4 to 1.3.5 (#288)
Bumps [pandas](https://github.com/pandas-dev/pandas) from 1.3.4 to 1.3.5.
- [Release notes](https://github.com/pandas-dev/pandas/releases)
- [Changelog](https://github.com/pandas-dev/pandas/blob/master/RELEASE.md)
- [Commits](https://github.com/pandas-dev/pandas/compare/v1.3.4...v1.3.5)

---
updated-dependencies:
- dependency-name: pandas
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-12-14 13:49:55 +01:00
poe
4580d51ff3 test for argument; bug fix 2021-12-11 22:28:04 +01:00
poe28@gmx.net
4182b98493 tool for showing candle DB overview 2021-12-11 21:22:22 +01:00
Saleh Mir
bb3b54e2af fix issue with cython and fastapi 2021-12-08 18:12:42 +01:00
dependabot[bot]
befc52c4d3 Bump websocket-client from 1.2.1 to 1.2.3 (#284)
Bumps [websocket-client](https://github.com/websocket-client/websocket-client) from 1.2.1 to 1.2.3.
- [Release notes](https://github.com/websocket-client/websocket-client/releases)
- [Changelog](https://github.com/websocket-client/websocket-client/blob/master/ChangeLog)
- [Commits](https://github.com/websocket-client/websocket-client/compare/v1.2.1...v1.2.3)

---
updated-dependencies:
- dependency-name: websocket-client
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-12-08 10:28:07 +01:00
dependabot[bot]
53b7e4779f Bump ta-lib from 0.4.21 to 0.4.22 (#283)
Bumps [ta-lib](https://github.com/mrjbq7/ta-lib) from 0.4.21 to 0.4.22.
- [Release notes](https://github.com/mrjbq7/ta-lib/releases)
- [Changelog](https://github.com/mrjbq7/ta-lib/blob/master/CHANGELOG)
- [Commits](https://github.com/mrjbq7/ta-lib/compare/TA_Lib-0.4.21...TA_Lib-0.4.22)

---
updated-dependencies:
- dependency-name: ta-lib
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-12-08 10:27:56 +01:00
Saleh Mir
09fac79497 fix an issue with peewee's get_or_none() 2021-12-07 10:15:37 +01:00
Saleh Mir
af90ae84ed update frontend 2021-12-07 09:46:24 +01:00
Saleh Mir
61300d6d41 remove is_logged_in_to_jesse_trade as it is no longer needed 2021-12-07 09:46:19 +01:00
Saleh Mir
ce10251ca4 fix for database not being ready at start time to run the migrations (issue for first time docker usage) 2021-12-07 09:03:01 +01:00
Saleh Mir
b11c573d0c Don't run migrations if database is not ready yet 2021-12-07 08:38:04 +01:00
Saleh Mir
e08431d215 fix and issue in get_access_token() 2021-12-07 08:37:41 +01:00
Saleh Mir
3b50419d8d update frontend 2021-12-07 08:37:25 +01:00
Saleh Mir
5b977de2e1 remove login_jesse_trade and logout_jesse_trade routes 2021-12-06 12:25:34 +03:30
Saleh Mir
e040c40f6f update get_access_token to read from the .env file 2021-12-06 12:25:12 +03:30
Saleh Mir
6b8bc65263 Update installer.py 2021-12-06 10:31:25 +03:30
Saleh Mir
7400730c89 improve install-live command 2021-12-05 19:11:13 +03:30
Saleh Mir
227b166764 initial version of the install-live command 2021-12-05 17:03:34 +03:30
Saleh Mir
800d71ff48 update frontend files 2021-12-05 16:57:29 +03:30
Markus K
61885e85e8 Update stale.yml 2021-12-05 12:03:58 +01:00
Markus K
0f9f3cd561 Create stale.yml 2021-12-05 11:38:20 +01:00
Saleh Mir
0acff13cbd Merge pull request #280 from jcsaaddupuy/fix_research_get_candles
removes exchange.title() transformation in research/get_candles.py
2021-12-05 12:30:57 +03:30
dependabot[bot]
410a68c567 Bump quantstats from 0.0.46 to 0.0.47 (#281)
Bumps [quantstats](https://github.com/ranaroussi/quantstats) from 0.0.46 to 0.0.47.
- [Release notes](https://github.com/ranaroussi/quantstats/releases)
- [Changelog](https://github.com/ranaroussi/quantstats/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/ranaroussi/quantstats/commits)

---
updated-dependencies:
- dependency-name: quantstats
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-12-02 15:46:18 +01:00
Saleh Mir
c636102096 remove all commands except for "jesse run" 2021-12-02 18:09:40 +03:30
Saleh Mir
6c31456727 bump to 0.29.3 2021-12-01 11:53:24 +03:30
Saleh Mir
83c8a3c32f update frontend files 2021-12-01 11:45:28 +03:30
Saleh Mir
a191135052 fix a few bugs in the optimize mode 2021-12-01 11:26:50 +03:30
Saleh Mir
4d9bb206fb fix a bug where the index is sometimes wrong 2021-11-30 11:47:10 +03:30
Saleh Mir
0eb67ed090 don't log candle storage into DB anymore 2021-11-29 17:06:26 +03:30
Saleh Mir
79bad9dd17 fix typo 2021-11-29 16:46:34 +03:30
Saleh Mir
c0a6f0d182 Merge branch 'dashboard' into beta 2021-11-29 16:41:13 +03:30
Saleh Mir
a6f992d726 update frontend 2021-11-29 16:40:55 +03:30
Saleh Mir
a9bc53b516 store candles into db even on updates 2021-11-29 13:26:14 +03:30
Saleh Mir
f5150cbeca add on_conflict_replace for candles 2021-11-29 13:25:05 +03:30
Saleh Mir
cd2967ad63 add latest improvements of the frontend 2021-11-28 11:06:14 +03:30
Saleh Mir
882430b3be fix: allow logging of Order messages being optional 2021-11-28 11:05:51 +03:30
Saleh Mir
a737ffc9c8 allow setting the port number in the .env file 2021-11-26 20:50:46 +03:30
Saleh Mir
4278da0932 add recent updates of the frontend 2021-11-26 20:29:30 +03:30
dependabot[bot]
0c322291e5 Bump scipy from 1.7.2 to 1.7.3 (#279)
Bumps [scipy](https://github.com/scipy/scipy) from 1.7.2 to 1.7.3.
- [Release notes](https://github.com/scipy/scipy/releases)
- [Commits](https://github.com/scipy/scipy/compare/v1.7.2...v1.7.3)

---
updated-dependencies:
- dependency-name: scipy
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-25 18:55:57 +01:00
Markus
bda7762eba Remove .txt and json output of optimization results. Make CSV default. 2021-11-25 18:43:35 +01:00
jcsaaddupuy
db117cb7b9 removes exchange.title() transformation in research/get_candles.py 2021-11-25 15:10:38 +01:00
Saleh Mir
de5cb75e09 fix "'NoneType' object has no attribute 'orders'" error 2021-11-25 17:33:10 +03:30
Saleh Mir
5747b71a8f silent warning 2021-11-25 11:28:02 +03:30
Saleh Mir
39dd97d8bd fix an error for tests 2021-11-25 11:22:34 +03:30
Saleh Mir
3f93c01eef add guide for security 2021-11-22 19:15:09 +03:30
Saleh Mir
504ca51f58 comment the code for other plots 2021-11-19 17:07:23 +03:30
Saleh Mir
58c64c57df bump version 2021-11-19 10:05:17 +03:30
Markus
1c5d77d5d6 Merge remote-tracking branch 'origin/master' 2021-11-18 20:06:30 +01:00
Markus
9af852503d Fix round None error. 2021-11-18 20:05:30 +01:00
Markus
cc8595c782 Fix round None error. 2021-11-18 20:03:39 +01:00
Saleh Mir
553aa93594 update text 2021-11-18 20:11:40 +03:30
Saleh Mir
6b47213fa6 Merge branch 'dashboard' into beta 2021-11-18 19:27:49 +03:30
Saleh Mir
fdf426844c Update README.md 2021-11-18 19:27:43 +03:30
Saleh Mir
b3e243ea32 Merge pull request #275 from bugraaydogar/master
Pass database parameter to get rid of authentication issues
2021-11-18 15:01:30 +03:30
Saleh Mir
f39bcf6976 Merge branch 'dashboard' into beta 2021-11-18 13:58:48 +03:30
Saleh Mir
d8813bfade refactor database 2021-11-18 13:57:05 +03:30
Buğra Aydoğar
0552443541 Pass database parameter to get rid of authentication issues 2021-11-18 12:50:13 +03:00
Saleh Mir
c47d2832fb temp code 2021-11-18 12:20:42 +03:30
Saleh Mir
101a0049cd set multiprocessing process type to spawn 2021-11-18 12:15:26 +03:30
Saleh Mir
c364a2e65e remove statsmodels as a dependancy 2021-11-18 12:13:57 +03:30
Saleh Mir
9a50a4bb0b Merge branch 'dashboard' into beta 2021-11-17 21:47:02 +03:30
Saleh Mir
ed3647359d disable SSL for postgres 2021-11-17 21:39:37 +03:30
Saleh Mir
b3afd401e7 bring back termiante() on process cancelling 2021-11-17 21:11:28 +03:30
Saleh Mir
0f64154319 bring back previous commit 2021-11-17 21:04:57 +03:30
Saleh Mir
d4d30f590d Merge branch 'beta' into dashboard 2021-11-17 21:03:59 +03:30
Saleh Mir
7ea302ca41 try not completely terminating 2021-11-17 21:03:41 +03:30
Saleh Mir
a4270c2ee4 Update db.py 2021-11-17 20:54:19 +03:30
Saleh Mir
5bd98601e1 update database initiation 2021-11-17 20:52:39 +03:30
Saleh Mir
60f51b91be fix 2021-11-17 20:34:03 +03:30
Saleh Mir
bb884c2904 handle database open/close at data endpoints 2021-11-17 18:32:45 +03:30
Saleh Mir
824198188a refactor database handling 2021-11-17 18:24:37 +03:30
dependabot[bot]
80f67edd6c Bump quantstats from 0.0.45 to 0.0.46 (#273)
Bumps [quantstats](https://github.com/ranaroussi/quantstats) from 0.0.45 to 0.0.46.
- [Release notes](https://github.com/ranaroussi/quantstats/releases)
- [Changelog](https://github.com/ranaroussi/quantstats/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/ranaroussi/quantstats/commits)

---
updated-dependencies:
- dependency-name: quantstats
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-17 01:53:54 +01:00
dependabot[bot]
c753832e49 Bump matplotlib from 3.4.3 to 3.5.0 (#272)
Bumps [matplotlib](https://github.com/matplotlib/matplotlib) from 3.4.3 to 3.5.0.
- [Release notes](https://github.com/matplotlib/matplotlib/releases)
- [Commits](https://github.com/matplotlib/matplotlib/compare/v3.4.3...v3.5.0)

---
updated-dependencies:
- dependency-name: matplotlib
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-17 01:53:42 +01:00
Saleh Mir
b4849f6608 bump version 2021-11-16 17:45:55 +03:30
Markus
c112965882 Add logs folder creation in make_project. 2021-11-16 14:32:30 +01:00
Markus
fa08f6674a Remove register_custom_exception_handler for make_project. 2021-11-16 14:21:05 +01:00
Markus
ca7ae8d7d6 Exclude storage/logs from template and great the dir on init. 2021-11-16 14:08:37 +01:00
Markus K
c404805c8b Don't pin minor version. 2021-11-16 12:15:32 +01:00
Markus K
695cec2311 Don't pin minor version. 2021-11-16 12:15:12 +01:00
dependabot[bot]
cf7e5845ac Bump statsmodels from 0.13.0 to 0.13.1 (#271)
Bumps [statsmodels](https://github.com/statsmodels/statsmodels) from 0.13.0 to 0.13.1.
- [Release notes](https://github.com/statsmodels/statsmodels/releases)
- [Changelog](https://github.com/statsmodels/statsmodels/blob/main/CHANGES.md)
- [Commits](https://github.com/statsmodels/statsmodels/compare/v0.13.0...v0.13.1)

---
updated-dependencies:
- dependency-name: statsmodels
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-16 12:12:59 +01:00
Markus
a2aafe2918 The package only includes directories with __init__. Fixed logs directory not being created. 2021-11-15 13:22:12 +01:00
Markus
ea24a3b307 Make python version compatible with 3.10 2021-11-14 14:08:16 +01:00
Markus K
2e6167e956 Update required packages 2021-11-14 13:55:17 +01:00
Markus K
7d81da68a7 Update python-package.yml 2021-11-14 12:53:38 +01:00
Markus K
99d371e508 Fix numba 3.10 condition. 2021-11-14 12:36:24 +01:00
Markus K
cacfe08ea4 Update python-package.yml 2021-11-14 12:32:18 +01:00
Markus K
d343414ede Don't install numb on 3.10 2021-11-14 12:31:55 +01:00
Markus K
2a966ff9c0 Test 3.10 - use string. 2021-11-14 12:09:51 +01:00
Markus K
cc8d496bf8 Test 3.10 2021-11-14 12:08:04 +01:00
dependabot[bot]
b3f5a2cd8e Bump psycopg2-binary from 2.9.1 to 2.9.2 (#270)
Bumps [psycopg2-binary](https://github.com/psycopg/psycopg2) from 2.9.1 to 2.9.2.
- [Release notes](https://github.com/psycopg/psycopg2/releases)
- [Changelog](https://github.com/psycopg/psycopg2/blob/master/NEWS)
- [Commits](https://github.com/psycopg/psycopg2/commits)

---
updated-dependencies:
- dependency-name: psycopg2-binary
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-14 12:07:28 +01:00
Markus
989f2b0d72 1m * highest timeframe are needed here. 2021-11-13 13:50:31 +01:00
Markus
19e944fa32 Refactors. 2021-11-12 18:36:21 +01:00
Markus
eb38fd8ac5 Remove 3D and 1 Week timeframe as those don't behave the same as on the exchange. 2021-11-12 13:45:19 +01:00
Markus
664f32a133 Remove 3D and 1 Week timeframe as those don't behave the same as on the exchange. 2021-11-12 13:43:43 +01:00
Markus
7ac2c1e758 Use tab delimiter, as sometimes DNA chars mess up the CSV. 2021-11-12 12:07:57 +01:00
Saleh Mir
44f4002ec6 bump version 2021-11-12 12:45:37 +03:30
Saleh Mir
4b254d7a13 update html files 2021-11-12 10:48:35 +03:30
Saleh Mir
83dec4e2d6 update installation instructions 2021-11-11 22:08:30 +03:30
Saleh Mir
4a3e7c4c77 fix database 2021-11-11 21:29:37 +03:30
Saleh Mir
18e26f3f8e Update __init__.py 2021-11-11 21:20:30 +03:30
Saleh Mir
07c8fa463f set simplejson at v3.16.0 2021-11-11 21:09:40 +03:30
Saleh Mir
5d7459631d update simplejson 2021-11-11 21:03:14 +03:30
Saleh Mir
7b392bdf57 update with new frontend built 2021-11-11 19:11:04 +03:30
Saleh Mir
bfab35d51d allow requests from * 2021-11-11 19:10:36 +03:30
Saleh Mir
e4de8e5a18 stop the status_checker time loop to not break early live sessions 2021-11-11 17:59:38 +03:30
Saleh Mir
ffbfe03e60 Merge branch 'master' into dashboard 2021-11-11 16:22:29 +03:30
Saleh Mir
d6928c2f1a bump version 2021-11-11 12:26:08 +03:30
Saleh Mir
7befe7b0e3 handle exchange driver not initiated yet (rare) issues 2021-11-11 10:35:32 +03:30
Saleh Mir
e4a15ae594 rename function 2021-11-10 18:26:10 +03:30
Saleh Mir
77123dbfb6 tiny refacor 2021-11-10 18:08:55 +03:30
Saleh Mir
f2db32dcac fix order price of market orders 2021-11-10 18:08:28 +03:30
dependabot[bot]
ae9001afb9 Bump pywavelets from 1.1.1 to 1.2.0 (#269)
Bumps [pywavelets](https://github.com/PyWavelets/pywt) from 1.1.1 to 1.2.0.
- [Release notes](https://github.com/PyWavelets/pywt/releases)
- [Commits](https://github.com/PyWavelets/pywt/compare/v1.1.1...v1.2.0)

---
updated-dependencies:
- dependency-name: pywavelets
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-10 12:32:21 +01:00
Saleh Mir
add0e5c798 Merge branch 'refactor-migrator' into dashboard 2021-11-10 12:02:57 +03:30
Saleh Mir
1c8ee6e87d fix str_or_none() when handling str inputs 2021-11-10 12:02:17 +03:30
Saleh Mir
43156453bc fix migration item 2021-11-10 12:01:36 +03:30
Saleh Mir
fa76f753e8 refactor text format 2021-11-10 11:43:49 +03:30
Saleh Mir
9aa63a5fe6 update action types 2021-11-10 11:40:04 +03:30
Saleh Mir
a259707594 refactor
refactor names
2021-11-10 11:37:22 +03:30
Saleh Mir
21021075d6 refactor
refactor names
2021-11-10 11:16:36 +03:30
morteza-koohgard
fc586ae475 refactor the migrator service
fix a bug

small change

refactor migrator service

work on migration (not finished)

refactor migrator

modify migrator
2021-11-10 11:02:12 +03:30
Markus K
bb6f42af11 Update feature_request.md 2021-11-09 21:02:03 +01:00
Markus K
ec6eda3229 Update bug_report.md 2021-11-09 20:59:40 +01:00
Saleh Mir
966928bc67 fix timestamps in equity curve 2021-11-09 18:24:26 +03:30
Saleh Mir
9cfa28f262 Merge pull request #267 from jesse-ai/dependabot/pip/scipy-1.7.2
Bump scipy from 1.7.1 to 1.7.2
2021-11-09 18:04:53 +03:30
Markus
70aa3525ba Merge remote-tracking branch 'origin/dashboard' into dashboard 2021-11-09 15:16:04 +01:00
Markus
dcf83bd28b Remove unnecessary loop. 2021-11-09 15:15:56 +01:00
Markus
be7ee9afb5 Merge remote-tracking branch 'origin/master' 2021-11-09 15:12:28 +01:00
Markus
fd4f2b9347 Remove unnecessary loop. 2021-11-09 15:12:16 +01:00
Markus
e0f76db00d Remove unnecessary loop. 2021-11-09 15:10:33 +01:00
Saleh Mir
6c16b4b9b0 remote debugging code 2021-11-09 13:15:51 +03:30
Saleh Mir
beea05cd15 implement setting dna using the dna() method in the strategy file instead 2021-11-09 13:14:56 +03:30
dependabot[bot]
392cb82287 Bump scipy from 1.7.1 to 1.7.2
Bumps [scipy](https://github.com/scipy/scipy) from 1.7.1 to 1.7.2.
- [Release notes](https://github.com/scipy/scipy/releases)
- [Commits](https://github.com/scipy/scipy/compare/v1.7.1...v1.7.2)

---
updated-dependencies:
- dependency-name: scipy
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-08 23:23:13 +00:00
Saleh Mir
dfc9bd59bc bump version 2021-11-08 20:10:38 +03:30
Saleh Mir
57e60a9042 notify on self.log 2021-11-08 20:10:19 +03:30
Markus
9d48160070 Remove storage/logs dir creation as this folder already exists in the project template. 2021-11-08 16:55:21 +01:00
Saleh Mir
bfb5fcf2f8 remove duplicate dependancies 2021-11-08 19:00:30 +03:30
Saleh Mir
3c1980a5bb Update .gitignore 2021-11-08 18:59:48 +03:30
Markus K
abffaa5492 Update codeql-analysis.yml 2021-11-08 10:35:37 +01:00
Markus K
6452a29727 Create codeql-analysis.yml 2021-11-08 10:26:31 +01:00
Saleh Mir
e70a764655 add fields for migrations 2021-11-08 11:06:25 +03:30
Saleh Mir
3b90ee48e0 refactor the migration commad 2021-11-08 10:53:00 +03:30
Markus
860527f9a8 Merge dictionary assignment with declaration(merge-dict-assign)
Inline variable that is immediately returned(inline-immediately-returned-variable)
2021-11-07 13:03:14 +01:00
Markus
dab5b47426 Use x is None rather than x == None(none-compare) 2021-11-07 13:02:37 +01:00
Markus
0a4f443b29 Simplify conditional into switch-like form(switch) 2021-11-07 13:02:26 +01:00
Markus
86e7e72fe3 Merge dictionary assignment with declaration(merge-dict-assign)
Inline variable that is immediately returned(inline-immediately-returned-variable)
2021-11-07 13:02:12 +01:00
Markus
faced4ba56 Inline variable that is immediately returned(inline-immediately-returned-variable) 2021-11-07 13:00:12 +01:00
Markus
ba244d3b01 Merge duplicate blocks in conditional(merge-duplicate-blocks)
Remove redundant conditional(remove-redundant-if)
Replace multiple comparisons of same variable with `in` operator(merge-comparisons)
2021-11-07 12:59:48 +01:00
Markus
1584470345 Swap if/else branches(swap-if-else-branches)
Remove unnecessary else after guard condition(remove-unnecessary-else)
2021-11-07 12:58:29 +01:00
Markus
e63afc9211 Convert for loop into list comprehension(list-comprehension)
Inline variable that is immediately returned(inline-immediately-returned-variable)
2021-11-07 12:58:13 +01:00
Markus
a2ff8bf355 Inline variable that is immediately returned(inline-immediately-returned-variable) 2021-11-07 12:58:02 +01:00
Markus
73b4ebccc4 Use items() to directly unpack dictionary values(use-dict-items) 2021-11-07 12:56:54 +01:00
Markus
80f1296e8c Inline variable that is immediately returned(inline-immediately-returned-variable) 2021-11-07 12:55:45 +01:00
Markus
4fde6819cd Replace if statement with if expression(assign-if-exp)
Simplify if expression by using or(or-if-exp-identity)
2021-11-07 12:55:12 +01:00
Markus
821205c60e Simplify unnecessary nesting, casting and constant values in f-strings(simplify-fstring-formatting)
Swap positions of nested conditionals(swap-nested-ifs)
Hoist repeated code outside conditional statement(hoist-statement-from-if)
Replace if statement with if expression(assign-if-exp)
2021-11-07 12:54:40 +01:00
Markus
4f0cc3b112 Merge dictionary assignment with declaration(merge-dict-assign)
Inline variable that is immediately returned(inline-immediately-returned-variable)
2021-11-07 12:37:44 +01:00
Markus
3817c97df1 Merge dictionary assignment with declaration(merge-dict-assign) 2021-11-07 12:37:22 +01:00
Markus
59ea893ce2 Use x is None rather than x == None(none-compare) 2021-11-07 12:37:08 +01:00
Markus
18f7844368 Simplify conditional into switch-like form(switch) 2021-11-07 12:36:54 +01:00
Markus
6e78080ca2 Merge dictionary assignment with declaration(merge-dict-assign)
Inline variable that is immediately returned(inline-immediately-returned-variable)
2021-11-07 12:36:23 +01:00
Markus
a084b27ed3 Use set when checking membership of a collection of literals(collection-into-set) 2021-11-07 12:28:15 +01:00
Markus
01ad214965 Swap if/else branches(swap-if-else-branches)
Remove unnecessary else after guard condition(remove-unnecessary-else)
2021-11-07 12:27:57 +01:00
Markus
9f1c0e32d4 Swap if/else branches(swap-if-else-branches)
Remove unnecessary else after guard condition(remove-unnecessary-else)
2021-11-07 12:27:43 +01:00
Markus
2c14305de7 Merge duplicate blocks in conditional(merge-duplicate-blocks)
Remove redundant conditional(remove-redundant-if)
Replace multiple comparisons of same variable with `in` operator(merge-comparisons)
2021-11-07 12:26:27 +01:00
Markus
5e3842d0fb Convert for loop into list comprehension(list-comprehension)
Inline variable that is immediately returned(inline-immediately-returned-variable)
2021-11-07 12:20:55 +01:00
Markus
511a8933f9 Simplify if expression by using or(or-if-exp-identity) 2021-11-07 12:20:22 +01:00
Markus
289c0710f2 Simplify unnecessary nesting, casting and constant values in f-strings(simplify-fstring-formatting) 2021-11-07 12:19:51 +01:00
Markus
b7eea30bbd Simplify sequence comparison(simplify-len-comparison) 2021-11-07 12:19:13 +01:00
Markus
6943739043 Convert for loop into list comprehension(list-comprehension)
Inline variable that is immediately returned(inline-immediately-returned-variable)
2021-11-07 12:18:53 +01:00
Markus
1cf932d5f7 Use any() instead of for loop(use-any) 2021-11-07 12:18:01 +01:00
Markus
b16f74d6a8 Replace f-string with no interpolated values with string(remove-redundant-fstring) 2021-11-07 12:16:57 +01:00
Markus
1d6f0b1eeb Replace f-string with no interpolated values with string(remove-redundant-fstring) 2021-11-07 12:16:44 +01:00
Markus
19c22d51aa Replace f-string with no interpolated values with string(remove-redundant-fstring) 2021-11-07 12:16:20 +01:00
Markus
a893838cef Convert for loop into list comprehension(list-comprehension)
Inline variable that is immediately returned(inline-immediately-returned-variable)
2021-11-07 12:15:11 +01:00
Markus
455442260a Use with when opening file to ensure closure(ensure-file-closed) 2021-11-07 12:14:39 +01:00
Markus
12a962debf Convert for loop into list comprehension(list-comprehension)
Inline variable that is immediately returned(inline-immediately-returned-variable)
2021-11-07 12:12:52 +01:00
Markus
d6132e0dd8 Simplify boolean if expression(boolean-if-exp-identity) 2021-11-07 12:11:58 +01:00
Markus
bac2f1ca12 Convert for loop into list comprehension(list-comprehension)
Inline variable that is immediately returned(inline-immediately-returned-variable)
2021-11-07 12:11:47 +01:00
Markus
c40d029d22 Replace if statement with if expression(assign-if-exp)
Simplify if expression by using or(or-if-exp-identity)
2021-11-07 12:08:20 +01:00
Markus
5c63f19f5d Simplify unnecessary nesting, casting and constant values in f-strings(simplify-fstring-formatting)
Convert for loop into list comprehension(list-comprehension)
2021-11-07 12:05:34 +01:00
Markus
bd7982cb9d Simplify unnecessary nesting, casting and constant values in f-strings(simplify-fstring-formatting)
Replace unused for index with underscore(for-index-underscore)
2021-11-07 12:05:10 +01:00
Markus
f7c7b64b44 Simplify unnecessary nesting, casting and constant values in f-strings 2021-11-07 12:04:12 +01:00
Markus
941630fcf5 Simplify unnecessary nesting, casting and constant values in f-strings 2021-11-07 12:04:02 +01:00
Markus
55eb7835b8 Inline variable that is immediately returned 2021-11-07 12:03:24 +01:00
Markus
28561472da Inline variable that is immediately returned 2021-11-07 12:02:26 +01:00
Markus
2dc59f6cab Convert for loop into list comprehension
Inline variable that is immediately returned
2021-11-07 12:02:01 +01:00
Markus
f78f352cb6 Inline variable that is immediately returned 2021-11-07 12:01:17 +01:00
Markus
d922f9875d Inline variable that is immediately returned 2021-11-07 11:59:22 +01:00
Markus
9e316d8e67 Use items() to directly unpack dictionary values. 2021-11-07 11:57:43 +01:00
Saleh Mir
883a598db4 add ENV names for FTX Futures 2021-11-06 17:15:47 +01:00
Saleh Mir
53bfbd4025 add convert_to_env_name() helper 2021-11-06 17:15:34 +01:00
dependabot[bot]
06d4dcbee2 Bump numpy from 1.21.3 to 1.21.4 (#266)
Bumps [numpy](https://github.com/numpy/numpy) from 1.21.3 to 1.21.4.
- [Release notes](https://github.com/numpy/numpy/releases)
- [Changelog](https://github.com/numpy/numpy/blob/main/doc/HOWTO_RELEASE.rst.txt)
- [Commits](https://github.com/numpy/numpy/compare/v1.21.3...v1.21.4)

---
updated-dependencies:
- dependency-name: numpy
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-06 15:30:18 +01:00
Saleh Mir
54dfb92c3a fix path of log file for live mode 2021-11-05 08:38:17 +01:00
Saleh Mir
8b21948f57 remove "{jh.now(True)}--" from name of the log files 2021-11-05 08:02:10 +01:00
Saleh Mir
aabbb2c433 remove comments 2021-11-05 07:59:22 +01:00
Saleh Mir
3ec8852e81 make session_id optional for exception reports 2021-11-05 07:56:39 +01:00
Saleh Mir
b197ce3c38 attach exchange_log if there's any 2021-11-05 07:34:21 +01:00
Saleh Mir
e121c24d38 Merge branch 'dashboard' of github.com:jesse-ai/jesse into dashboard 2021-11-04 16:46:06 +01:00
Saleh Mir
bb30875850 refactor imports 2021-11-04 16:45:51 +01:00
Saleh Mir
50f88a4d47 use the new logger 2021-11-04 16:45:34 +01:00
Saleh Mir
8704051d43 refactor log handling to support multiple loggers (with differnet files) 2021-11-04 16:43:34 +01:00
Saleh Mir
0977d8144c create make_directory() helper 2021-11-04 16:43:13 +01:00
morteza-koohgard
412b7d4b8d add session id to orders table 2021-11-04 18:18:43 +03:30
Saleh Mir
50f68cf898 reorder imports to prevent circular imports issue 2021-11-04 14:06:41 +01:00
Saleh Mir
d5265aa627 tiny refactor 2021-11-04 14:06:28 +01:00
Saleh Mir
13ef3fb99a change the order of imports to prevent conflict 2021-11-04 10:51:19 +01:00
Saleh Mir
d81cc70422 check for termination on every second instead 2021-11-04 09:51:37 +01:00
morteza-koohgard
22ab5a341d fix sending of exception file 2021-11-04 10:20:27 +03:30
dependabot[bot]
f79c79bdef Bump quantstats from 0.0.44 to 0.0.45 (#263)
Bumps [quantstats](https://github.com/ranaroussi/quantstats) from 0.0.44 to 0.0.45.
- [Release notes](https://github.com/ranaroussi/quantstats/releases)
- [Changelog](https://github.com/ranaroussi/quantstats/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/ranaroussi/quantstats/commits)

---
updated-dependencies:
- dependency-name: quantstats
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-11-03 13:42:50 +01:00
Saleh Mir
7d5bdc04f0 Merge branch 'dashboard' of github.com:jesse-ai/jesse into dashboard 2021-11-03 11:25:56 +01:00
Saleh Mir
5c70f0e124 pass around log files in exception reports 2021-11-03 11:25:50 +01:00
morteza-koohgard
6ee96a3646 Merge branch 'migration' into dashboard 2021-11-03 08:18:08 +03:30
morteza-koohgard
551cd9321c remove argument of migrator
remove argument of migrator
2021-11-02 21:47:43 +03:30
morteza-koohgard
2657ff8fe7 add migrator service to add new field 2021-11-02 16:37:41 +03:30
morteza-koohgard
1ca15c00f2 add jesse command for migration 2021-11-02 16:37:29 +03:30
Saleh Mir
c85918bc04 improve text after optimize mode is done 2021-11-02 13:58:06 +01:00
Saleh Mir
b0c3878da5 broadcast messages instead of print 2021-11-02 11:22:09 +01:00
Saleh Mir
4686438fc2 update optimize mdoe 2021-11-02 11:21:48 +01:00
Saleh Mir
b1c8581e88 tiny refactor 2021-11-02 08:31:44 +01:00
Saleh Mir
9ee2a7508e disable optimize session resumsion stuff 2021-11-02 08:30:43 +01:00
Saleh Mir
963c886738 small refactors 2021-11-02 08:26:31 +01:00
Saleh Mir
2b77067ce5 replace prints with alert broadcasts 2021-11-02 08:22:45 +01:00
Saleh Mir
2a7f4d2fc3 update optimize mode 2021-11-01 16:56:19 +01:00
Saleh Mir
35e0353139 update optimize mode 2021-11-01 09:25:16 +01:00
Saleh Mir
a783576960 remove unused imports 2021-10-29 15:51:34 +02:00
Saleh Mir
77dd120d36 fix tests 2021-10-29 15:50:19 +02:00
Saleh Mir
68f3cc7636 fix issue of creating new jesse-project 2021-10-29 15:47:12 +02:00
dependabot[bot]
1b6b026c27 Bump peewee from 3.14.7 to 3.14.8 (#262)
Bumps [peewee](https://github.com/coleifer/peewee) from 3.14.7 to 3.14.8.
- [Release notes](https://github.com/coleifer/peewee/releases)
- [Changelog](https://github.com/coleifer/peewee/blob/master/CHANGELOG.md)
- [Commits](https://github.com/coleifer/peewee/compare/3.14.7...3.14.8)

---
updated-dependencies:
- dependency-name: peewee
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-29 12:36:39 +02:00
Saleh Mir
e0edba6f1d remove unused print 2021-10-29 12:24:13 +02:00
Saleh Mir
0501e64824 display execution time and success alert after backtest 2021-10-29 12:23:44 +02:00
dependabot[bot]
f40a9bea66 Bump peewee from 3.14.4 to 3.14.7 (#261)
Bumps [peewee](https://github.com/coleifer/peewee) from 3.14.4 to 3.14.7.
- [Release notes](https://github.com/coleifer/peewee/releases)
- [Changelog](https://github.com/coleifer/peewee/blob/master/CHANGELOG.md)
- [Commits](https://github.com/coleifer/peewee/compare/3.14.4...3.14.7)

---
updated-dependencies:
- dependency-name: peewee
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-28 12:27:55 +02:00
Saleh Mir
4987b6d3c7 add aveage exeution time per iteration in optmize mode 2021-10-28 10:20:22 +02:00
Saleh Mir
878e46bf1d rename property 2021-10-28 09:53:36 +02:00
Saleh Mir
d67e7ca10a rename Genetics.py => Optimize.py 2021-10-27 19:03:05 +02:00
Saleh Mir
3a2e54ca19 user our pwn progressbar for optimize mode 2021-10-27 18:44:03 +02:00
Saleh Mir
a03f255a71 use our own progressbar for import-candle smode 2021-10-27 18:38:07 +02:00
Saleh Mir
33d954b78c add better hanlding of "finished" cases 2021-10-27 18:37:56 +02:00
Saleh Mir
bd56604a9f use our own progressbar 2021-10-27 17:59:53 +02:00
Saleh Mir
c1f08c837a implement our own Progressbar class 2021-10-27 17:42:30 +02:00
Saleh Mir
b738629f28 add type 2021-10-27 17:42:03 +02:00
Saleh Mir
58ecbaaaba add supoprt for dynamic optimal_trades and cpu_cores options 2021-10-26 17:20:37 +02:00
Saleh Mir
cbd510b4c8 refactor config handling 2021-10-26 12:37:28 +02:00
dependabot[bot]
12ab5932ad Bump arrow from 1.2.0 to 1.2.1 (#260)
Bumps [arrow](https://github.com/arrow-py/arrow) from 1.2.0 to 1.2.1.
- [Release notes](https://github.com/arrow-py/arrow/releases)
- [Changelog](https://github.com/arrow-py/arrow/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/arrow-py/arrow/compare/1.2.0...1.2.1)

---
updated-dependencies:
- dependency-name: arrow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-26 09:59:34 +02:00
dependabot[bot]
f8e3194fe9 Bump quantstats from 0.0.43 to 0.0.44 (#259)
Bumps [quantstats](https://github.com/ranaroussi/quantstats) from 0.0.43 to 0.0.44.
- [Release notes](https://github.com/ranaroussi/quantstats/releases)
- [Changelog](https://github.com/ranaroussi/quantstats/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/ranaroussi/quantstats/commits)

---
updated-dependencies:
- dependency-name: quantstats
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-26 09:59:21 +02:00
Saleh Mir
e7b7d28b91 handle unit tests 2021-10-25 10:00:20 +02:00
Saleh Mir
7130a38ab5 bump version 2021-10-23 21:51:24 +02:00
Saleh Mir
704d5a9e48 replace broker.stop_loss_at usage with broker.reduce_position_at which is smarter 2021-10-23 21:45:18 +02:00
Saleh Mir
183557e4b1 round exiting orders to be MARKET orders if the price diff is very tiny 2021-10-23 21:24:23 +02:00
Saleh Mir
4584f13934 simple refactors 2021-10-22 16:02:19 +02:00
Saleh Mir
f26eff4fdc pass actual parameters of the opitmize mode 2021-10-22 16:00:21 +02:00
Saleh Mir
d960df58af initial implementation of optimize mode on the dashboard branch
refactor optimize mode [part 1]

implement cancel-optimize mode endpoint

implement cancel-optimize mode endpoint
2021-10-22 15:56:18 +02:00
dependabot[bot]
7cb101649f Bump numpy from 1.21.2 to 1.21.3 (#258)
Bumps [numpy](https://github.com/numpy/numpy) from 1.21.2 to 1.21.3.
- [Release notes](https://github.com/numpy/numpy/releases)
- [Changelog](https://github.com/numpy/numpy/blob/main/doc/HOWTO_RELEASE.rst.txt)
- [Commits](https://github.com/numpy/numpy/compare/v1.21.2...v1.21.3)

---
updated-dependencies:
- dependency-name: numpy
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-21 11:44:59 +02:00
dependabot[bot]
c9ec5ec7ed Bump pandas from 1.3.3 to 1.3.4 (#257)
Bumps [pandas](https://github.com/pandas-dev/pandas) from 1.3.3 to 1.3.4.
- [Release notes](https://github.com/pandas-dev/pandas/releases)
- [Changelog](https://github.com/pandas-dev/pandas/blob/master/RELEASE.md)
- [Commits](https://github.com/pandas-dev/pandas/compare/v1.3.3...v1.3.4)

---
updated-dependencies:
- dependency-name: pandas
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-21 11:44:02 +02:00
Saleh Mir
9dff005c72 add proper termination handling 2021-10-21 10:15:31 +02:00
Saleh Mir
2b1573a952 add Termination exception 2021-10-21 10:13:50 +02:00
Saleh Mir
7f05aca403 add get_pid() helper and improve str_or_none to support bytes 2021-10-20 10:49:54 +02:00
Saleh Mir
d1b4f4ee36 Update Genetics.py 2021-10-18 18:24:20 +02:00
Saleh Mir
60e5c8302c remove debugging code 2021-10-18 18:19:16 +02:00
Saleh Mir
36add74834 dirty fix to get the settlement_currency right for none-USDT pairs 2021-10-18 18:18:45 +02:00
Saleh Mir
4d41cecb48 dirty fix to get the settlement_currency right for none-USDT pairs 2021-10-18 17:23:32 +02:00
Saleh Mir
f12e29f6da modify text 2021-10-18 17:23:13 +02:00
Saleh Mir
50d0e96a7e broadcast progressbar and generalInfo events 2021-10-18 12:23:56 +02:00
Saleh Mir
f4ee4b444c initially add optimization endpoint 2021-10-15 19:04:54 +02:00
Saleh Mir
1c539e4473 fix function names 2021-10-15 12:49:32 +02:00
Saleh Mir
6745453b69 fix accidently removed code 2021-10-15 12:47:19 +02:00
Saleh Mir
c218d69f16 fix candles issue required for FTX to work 2021-10-15 12:34:07 +02:00
Saleh Mir
169f3c85c4 bump version 2021-10-14 16:03:00 +02:00
Saleh Mir
ccbc8697ff Merge branch 'master' of github.com:jesse-ai/jesse 2021-10-12 16:30:37 +02:00
Saleh Mir
629be96aa4 final fix for "no candles were passed?" 2021-10-12 16:28:39 +02:00
dependabot[bot]
265ec07e9c Bump click from 8.0.2 to 8.0.3 (#255)
Bumps [click](https://github.com/pallets/click) from 8.0.2 to 8.0.3.
- [Release notes](https://github.com/pallets/click/releases)
- [Changelog](https://github.com/pallets/click/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/click/compare/8.0.2...8.0.3)

---
updated-dependencies:
- dependency-name: click
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-12 11:26:54 +02:00
dependabot[bot]
e66cc22e05 Bump quantstats from 0.0.42 to 0.0.43 (#254)
Bumps [quantstats](https://github.com/ranaroussi/quantstats) from 0.0.42 to 0.0.43.
- [Release notes](https://github.com/ranaroussi/quantstats/releases)
- [Changelog](https://github.com/ranaroussi/quantstats/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/ranaroussi/quantstats/commits)

---
updated-dependencies:
- dependency-name: quantstats
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-12 11:26:38 +02:00
Saleh Mir
b20716f1dc reformat 2021-10-11 22:25:35 +02:00
Saleh Mir
74c2a7e17f Update charts.py 2021-10-11 20:18:59 +02:00
Saleh Mir
f1a0f5992c Merge branch 'master' into dashboard 2021-10-11 19:54:20 +02:00
Saleh Mir
8d59993999 improve config persistency 2021-10-11 19:37:01 +02:00
Saleh Mir
640fdd5132 bump version 2021-10-11 17:02:22 +02:00
Saleh Mir
a8d00455b2 remove debugging print 2021-10-11 17:01:48 +02:00
Saleh Mir
18c8960fdb fix the debugging code 2021-10-11 11:09:56 +02:00
Saleh Mir
3be52a20e7 bump version 2021-10-09 20:32:39 +02:00
Saleh Mir
5a83331bc0 add support for unit testing the live-trade plugin 2021-10-09 20:32:04 +02:00
Saleh Mir
2c5e48ac52 handle PARTIALLY_FILLED order status 2021-10-09 20:31:44 +02:00
Saleh Mir
09a16501ee implement "PARTIAL_FILLED" support 2021-10-09 19:39:17 +02:00
Saleh Mir
448face575 make self._open_position_orders and self._close_position_orders list again 2021-10-09 18:23:46 +02:00
Saleh Mir
394d4bd294 Merge branch 'master' of github.com:jesse-ai/jesse 2021-10-09 16:11:23 +02:00
Saleh Mir
713b7cc7a1 Merge branch 'refactor-closing-order-handling' 2021-10-09 16:11:13 +02:00
Saleh Mir
9ce26a3ef7 add current_1m_candle_timestamp() helper 2021-10-09 16:08:37 +02:00
dependabot[bot]
e9dba8d039 Bump click from 8.0.1 to 8.0.2 (#253)
Bumps [click](https://github.com/pallets/click) from 8.0.1 to 8.0.2.
- [Release notes](https://github.com/pallets/click/releases)
- [Changelog](https://github.com/pallets/click/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/click/compare/8.0.1...8.0.2)

---
updated-dependencies:
- dependency-name: click
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-09 13:23:11 +02:00
dependabot[bot]
8cbe3badc0 Bump quantstats from 0.0.40 to 0.0.42 (#252)
Bumps [quantstats](https://github.com/ranaroussi/quantstats) from 0.0.40 to 0.0.42.
- [Release notes](https://github.com/ranaroussi/quantstats/releases)
- [Changelog](https://github.com/ranaroussi/quantstats/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/ranaroussi/quantstats/commits)

---
updated-dependencies:
- dependency-name: quantstats
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-09 13:23:01 +02:00
Saleh Mir
a718d1f03e for small price differences, use a MARKET order 2021-10-09 12:23:55 +02:00
Saleh Mir
865a7c578a add debugging code 2021-10-08 16:20:32 +02:00
Saleh Mir
2f72a1a285 add useful comments 2021-10-07 17:17:33 +02:00
Saleh Mir
f0fb5dc53a make self.log() a static method 2021-10-07 16:40:16 +02:00
Saleh Mir
acac321259 refactor _open_position_orders: use dict instead fo list 2021-10-07 16:39:22 +02:00
Saleh Mir
14b1b9441f replace on_take_profit and on_stop_loss with on_position_close 2021-10-07 16:12:04 +02:00
Saleh Mir
35b492a6b9 Merge branch 'master' of github.com:jesse-ai/jesse 2021-10-06 15:38:15 +02:00
Saleh Mir
d27cfea71e bump version 2021-10-06 15:37:05 +02:00
Saleh Mir
7b0d81c237 add more debugging code 2021-10-06 15:36:40 +02:00
Saleh Mir
7bb6020efb add a version file so we can later use it in the logs 2021-10-06 15:32:24 +02:00
dependabot[bot]
45594c6902 Bump quantstats from 0.0.38 to 0.0.40 (#251)
Bumps [quantstats](https://github.com/ranaroussi/quantstats) from 0.0.38 to 0.0.40.
- [Release notes](https://github.com/ranaroussi/quantstats/releases)
- [Changelog](https://github.com/ranaroussi/quantstats/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/ranaroussi/quantstats/commits)

---
updated-dependencies:
- dependency-name: quantstats
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-05 07:53:09 +02:00
Markus
527952a74b Fix "not defined" 2021-10-04 12:09:33 +02:00
Markus
b3e29d4703 Only calculate smart sharpe and sortino in the final report. 2021-10-04 12:00:28 +02:00
Markus
78bcba38c1 Add smart sharpe and sortino in optimize mode. 2021-10-04 11:03:25 +02:00
Markus
a2e20b6f91 Merge remote-tracking branch 'origin/master' 2021-10-04 11:00:00 +02:00
Markus
3bf11b37bf Add smart sharpe and sortino. 2021-10-04 10:59:38 +02:00
dependabot[bot]
4fffc22306 Bump pydash from 5.0.2 to 5.1.0 (#250)
Bumps [pydash](https://github.com/dgilland/pydash) from 5.0.2 to 5.1.0.
- [Release notes](https://github.com/dgilland/pydash/releases)
- [Changelog](https://github.com/dgilland/pydash/blob/develop/CHANGELOG.rst)
- [Commits](https://github.com/dgilland/pydash/compare/v5.0.2...v5.1.0)

---
updated-dependencies:
- dependency-name: pydash
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-04 10:54:17 +02:00
dependabot[bot]
2a59f618f9 Bump arrow from 1.1.1 to 1.2.0 (#249)
Bumps [arrow](https://github.com/arrow-py/arrow) from 1.1.1 to 1.2.0.
- [Release notes](https://github.com/arrow-py/arrow/releases)
- [Changelog](https://github.com/arrow-py/arrow/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/arrow-py/arrow/commits)

---
updated-dependencies:
- dependency-name: arrow
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-04 10:53:49 +02:00
dependabot[bot]
ade7faa5ad Bump statsmodels from 0.12.2 to 0.13.0 (#248)
Bumps [statsmodels](https://github.com/statsmodels/statsmodels) from 0.12.2 to 0.13.0.
- [Release notes](https://github.com/statsmodels/statsmodels/releases)
- [Changelog](https://github.com/statsmodels/statsmodels/blob/main/CHANGES.md)
- [Commits](https://github.com/statsmodels/statsmodels/compare/v0.12.2...v0.13.0)

---
updated-dependencies:
- dependency-name: statsmodels
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-04 10:53:35 +02:00
pyup.io bot
aaca7793e1 Update arrow from 1.1.1 to 1.2.0 (#247) 2021-10-04 10:53:24 +02:00
pyup.io bot
8fd612178f Update statsmodels from 0.12.2 to 0.13.0 (#246) 2021-10-04 10:53:12 +02:00
Markus K
bea0be323a Create dependabot.yml 2021-10-03 22:15:33 +02:00
Markus
3fc5e2d3fe Fix error when daily_return has to few data. 2021-10-03 20:53:15 +02:00
Markus
bf43a12cd6 Fix breaking change (periods_per_year) from quantstats. 2021-10-03 19:43:06 +02:00
Markus
50b492f155 Only calculate needed stats with quantstats. 2021-10-03 19:15:37 +02:00
Markus
2b9afaabbe Missing round for serenity. 2021-10-03 19:15:11 +02:00
Markus
ddb8252196 Remove print(). 2021-10-02 12:31:52 +02:00
Markus
44d2247515 Fix Max Drawdown: TypeError: type str doesn't define __round__ method 2021-10-02 11:19:49 +02:00
Markus
f3aaae3b97 Update quantstats, breaking change: trading_year_days -> periods_per_year and use new omega from quantstats 2021-10-02 09:26:17 +02:00
Markus K
67e954dd2d Add serenity 2021-10-01 20:57:41 +02:00
Markus K
a059e0adfa Add serenity ratio. 2021-10-01 20:57:26 +02:00
Markus K
e04c02b3b5 Quantstats metrics (#244)
* Replace empyrical with quantstats.

* Expose serenity_index

* Remove print.

* Add serenity index to output.

* Add serenity index to optimization.

* Update __init__.py
2021-10-01 20:55:30 +02:00
pyup.io bot
1314392d11 Update quantstats from 0.0.34 to 0.0.36 (#243) 2021-10-01 11:44:08 +02:00
Saleh Mir
ab7bb373a0 add debugging temp code 2021-09-27 11:11:14 +02:00
Saleh Mir
bbca8ea6bd add a helpful exception validation 2021-09-23 17:10:41 +02:00
Saleh Mir
2e2d9b03d4 add A helpful assertion for exchange initiations 2021-09-23 16:28:12 +02:00
Saleh Mir
dc101a1c82 cleanup 2021-09-23 16:27:46 +02:00
Saleh Mir
2e36e97d3a fix to pass unit tests 2021-09-23 12:14:04 +02:00
Saleh Mir
3029588e75 improve exception message 2021-09-23 12:13:55 +02:00
Saleh Mir
94914ad2ce Merge branch 'master' into dashboard 2021-09-23 11:54:03 +02:00
Saleh Mir
f89b34d7e9 bump version 2021-09-22 21:10:23 +02:00
Saleh Mir
47eecfab32 Merge remote-tracking branch 'origin/wavelet_denoise' 2021-09-22 21:10:03 +02:00
Saleh Mir
aab03cb9d9 bump version 2021-09-21 19:47:23 +02:00
Saleh Mir
3b728a8317 auto fix FTX routes with PERP in their symbol 2021-09-21 19:47:04 +02:00
Saleh Mir
a825e2ceb5 Merge branch 'master' of github.com:jesse-ai/jesse 2021-09-20 20:16:56 +02:00
Saleh Mir
b623aa9e36 add commented code that migh use soon 2021-09-20 16:42:44 +02:00
Markus
afcdc2e018 Fix typing. 2021-09-17 14:03:18 +02:00
Markus
aae6345813 Merge remote-tracking branch 'origin/master' 2021-09-17 13:54:22 +02:00
Markus
0e62855aa5 Add typing. 2021-09-17 13:54:13 +02:00
Markus K
5ae4039017 Add typing 2021-09-17 12:30:21 +02:00
Markus K
500e2797f8 Add missing typing. 2021-09-17 12:27:33 +02:00
Saleh Mir
7d14a3c152 bump patch version 2021-09-16 16:36:05 +02:00
Saleh Mir
ea6557ebd3 Merge branch 'master' of github.com:jesse-ai/jesse 2021-09-16 16:35:12 +02:00
Saleh Mir
30f3aeddef bump version 2021-09-16 16:34:40 +02:00
Saleh Mir
5625d97fa0 add str_or_none() helper 2021-09-16 16:34:35 +02:00
Saleh Mir
01eb8c46c4 improve handling of rejected orders 2021-09-16 16:34:29 +02:00
Markus
b9b7b96392 Check for existing DNA. 2021-09-15 15:58:24 +02:00
Markus
11847688e9 Check for existing DNA. 2021-09-15 15:33:23 +02:00
pyup.io bot
aa9ce33862 Update pandas from 1.3.2 to 1.3.3 (#241) 2021-09-13 13:59:45 +02:00
Markus K
3f7ac6e7c4 Add threshold_mode 2021-09-13 13:44:59 +02:00
Saleh Mir
1a8dfca8f7 Refactors for exchange handling 2021-09-12 17:44:29 +02:00
Saleh Mir
470447ddc7 Merge branch 'master' of github.com:jesse-ai/jesse 2021-09-10 11:06:44 +02:00
Saleh Mir
c3f1f7265a implement dump() helper and update dd() 2021-09-10 11:06:00 +02:00
Saleh Mir
5fb801df79 fix position table 2021-09-10 11:05:42 +02:00
pyup.io bot
e4bcae7bef Update numpy_groupies from 0.9.13 to 0.9.14 (#239) 2021-09-09 18:10:11 +02:00
Saleh Mir
65f60b8c1f add dd() and float_or_none() helpers 2021-09-09 15:45:48 +02:00
Saleh Mir
4f7d3508c2 add support or generating candles from trades stream 2021-09-06 20:01:10 +04:30
Saleh Mir
2928b83e16 add "FTX Futures" driver 2021-09-06 13:14:14 +04:30
Markus K
104744827c Update utils.py 2021-09-05 19:21:54 +02:00
Saleh Mir
b37f7af295 Merge branch 'Bybit-Driver' 2021-09-05 21:05:52 +04:30
Markus K
455c3b6b56 Remove leftover prints. 2021-09-05 15:25:52 +02:00
Markus
6d294a6750 Add wavelet denoising with test. 2021-09-05 15:22:04 +02:00
Markus
5a3b9aa44b Add PyWavelets as requirement. 2021-09-05 15:21:49 +02:00
Saleh Mir
2b05a1feac prevent the issue of missing candles when no volume is traded 2021-09-04 19:07:09 +04:30
pyup.io bot
7aa978fc60 Update pytest from 6.2.4 to 6.2.5 (#237) 2021-09-02 16:30:59 +02:00
Saleh Mir
d84a5453fd Revert "disable rma because it fails on devices without numba"
This reverts commit 97758b6248.
2021-08-31 18:32:27 +04:30
Saleh Mir
423ef882b8 Merge branch 'master' of github.com:jesse-ai/jesse 2021-08-31 18:31:58 +04:30
Saleh Mir
97758b6248 disable rma because it fails on devices without numba 2021-08-31 18:31:24 +04:30
Markus
a192e7c39f Merge remote-tracking branch 'origin/master' 2021-08-30 18:11:58 +02:00
Markus
43857b4401 Improve macdext test and improve matype support of macdext. 2021-08-30 18:11:41 +02:00
Markus
256e7d5123 Fix MAAQ. 2021-08-30 18:09:56 +02:00
Markus
ecbffe6a46 Fix Holt-Winter Moving Average. 2021-08-30 17:56:52 +02:00
Markus
be585cea44 Fix rma. 2021-08-30 17:27:39 +02:00
Saleh Mir
f01ef633b0 add config values for Bybit and its Testnet 2021-08-30 18:35:55 +04:30
Saleh Mir
72a4d71847 Merge branch 'Bybit-Driver' 2021-08-30 12:19:41 +04:30
Saleh Mir
0ef7b43cf9 Add driver "Testnet Bybit Perpetual" driver 2021-08-30 12:18:43 +04:30
Saleh Mir
c1cca2a0b3 add "Bybit Perpetual" driver 2021-08-30 12:15:17 +04:30
Markus
1c3cb990e4 Fix nan in macdext under certain conditions. 2021-08-29 13:47:02 +02:00
Markus
ece99024ef Make db connection more stable. 2021-08-29 13:46:12 +02:00
Saleh Mir
8ce260b267 Revert "add FTX driver for importing candles"
This reverts commit ad72d43bd9.
2021-08-27 20:42:08 +04:30
Saleh Mir
ad72d43bd9 add FTX driver for importing candles 2021-08-27 20:29:16 +04:30
Saleh Mir
fbe41c210e add disclaimer 2021-08-26 14:04:05 +04:30
Saleh Mir
ed7343e3c0 update 2021-08-26 13:51:26 +04:30
Saleh Mir
178e111087 add aiofiles as a requirement 2021-08-25 13:53:31 +04:30
Saleh Mir
d810d38207 create .env file on project creation 2021-08-25 13:52:07 +04:30
Saleh Mir
c0a31b7cdc ignore .env file 2021-08-25 13:45:32 +04:30
Saleh Mir
3136802e25 fix the issue with .env file 2021-08-25 13:39:53 +04:30
Saleh Mir
a08e40fbe3 add and use the is_jesse_project() helper 2021-08-25 13:39:34 +04:30
Markus K
c2cdd75668 Add git by default 2021-08-24 21:01:26 +02:00
Saleh Mir
8a8078bf09 replace with guide for installation 2021-08-23 13:50:37 +04:30
Saleh Mir
d1c0d05281 add the dashboard frontend files 2021-08-23 13:50:18 +04:30
Yunus S. Dede
1b0c95aab7 Tradingview's RMA moving average added (#234) 2021-08-23 10:14:50 +02:00
Saleh Mir
f5cc955bd4 implement /download endpoint for generated logs, charts, etc of backtests 2021-08-22 20:26:53 +04:30
Saleh Mir
06ca849cdf refactor packages into modules 2021-08-22 18:46:30 +04:30
Saleh Mir
b1d76d5183 force tests to pass 🤦‍♂️ 2021-08-22 18:45:29 +04:30
Saleh Mir
8aea5223a0 add general_info broadcast for backtest mode 2021-08-22 18:40:34 +04:30
Saleh Mir
d9a637a481 create session_id for all modes and use it for the name of the log file 2021-08-22 14:43:20 +04:30
Saleh Mir
eaf4308ed0 store backtest logs in the file instead of broadcasting them 2021-08-22 13:33:31 +04:30
Saleh Mir
29d421e31a remove comments and debugging code 2021-08-22 12:05:19 +04:30
Saleh Mir
25b4351b95 implement "report-exception" endpoint 2021-08-20 12:40:19 +04:30
Saleh Mir
93dc310408 implement "/feedback" endpoint 2021-08-19 18:50:00 +04:30
Saleh Mir
80cce88daa improve jesse project detection and error 2021-08-17 20:13:45 +04:30
Saleh Mir
7f5606d06d Implement "New Strategy" 2021-08-17 14:37:21 +04:30
pyup.io bot
dc95b24b61 Update pandas from 1.3.1 to 1.3.2 (#232) 2021-08-16 23:08:33 +02:00
pyup.io bot
24dc180a51 Update numpy from 1.21.1 to 1.21.2 (#233) 2021-08-16 23:08:24 +02:00
Saleh Mir
4be7ce1d61 implement login and logout for Jesse.Trade 2021-08-16 13:40:17 +04:30
Markus K
bd66d4f93b Update minmax.py 2021-08-15 14:11:39 +02:00
pyup.io bot
5b54e7abd2 Update matplotlib from 3.4.2 to 3.4.3 (#230) 2021-08-13 11:09:28 +02:00
pyup.io bot
8a2b627558 Update websocket-client from 1.2.0 to 1.2.1 (#231) 2021-08-13 11:08:55 +02:00
Markus
7725463e60 Fix metrics. 2021-08-12 18:34:55 +02:00
Saleh Mir
3d678d2395 implement consistent config system 2021-08-12 13:32:12 +04:30
pyup.io bot
e433cbe72b Update websocket-client from 1.1.1 to 1.2.0 (#229) 2021-08-11 22:06:24 +02:00
Saleh Mir
e3278af3ce add merge_dicts() helper 2021-08-11 14:18:04 +04:30
Markus K
780a1e8e74 Fix largest_winning_trade and largest_losing_trade 2021-08-11 10:35:52 +02:00
Saleh Mir
e16a4b5708 Merge branch 'master' of github.com:jesse-ai/jesse 2021-08-10 17:33:59 +04:30
Markus
4756529fa4 Fix typing. 2021-08-10 14:37:14 +02:00
Saleh Mir
7b68444e9b Merge branch 'master' of github.com:jesse-ai/jesse 2021-08-10 17:07:03 +04:30
Saleh Mir
cb35b43d2f bump version 2021-08-10 17:06:50 +04:30
Markus
95dc42af81 Add missing types and use uppercase for namedtuple. 2021-08-10 14:32:02 +02:00
Markus
fa5d1d6a7c Fix missing decorator. 2021-08-10 14:20:52 +02:00
Markus
b492093aa2 Fix comment. 2021-08-10 14:08:48 +02:00
Markus
9faf55f398 Fix comment. 2021-08-10 14:06:46 +02:00
Markus
38f88eb825 Make numba optional in hurst. 2021-08-10 13:20:41 +02:00
Saleh Mir
45ec37ceb4 disable hurst_exponent 2021-08-10 13:13:43 +04:30
Saleh Mir
c63fd82096 store orders in database for live mode 2021-08-09 21:20:06 +04:30
Saleh Mir
49085fbc12 implement get-logs endpoint 2021-08-08 18:22:38 +04:30
Saleh Mir
5e91aab844 refactor 2021-08-07 19:46:25 +04:30
Saleh Mir
db8e317f77 refactor logs 2021-08-07 19:42:58 +04:30
pyup.io bot
9890569743 Update websocket-client from 1.1.0 to 1.1.1 (#228) 2021-08-06 19:09:06 +02:00
Saleh Mir
2ecf98e428 implement authentication 2021-08-06 19:17:25 +04:30
Saleh Mir
54f5a31f5d only broadcast orders when updated 2021-08-05 13:27:47 +04:30
Markus
8786ce326c Merge remote-tracking branch 'origin/master' 2021-08-05 10:38:38 +02:00
Markus
cff0698a65 vwap needs volume and handle source_type external. 2021-08-05 10:38:29 +02:00
Saleh Mir
6e5cc29177 implement frontend config for live mode 2021-08-04 13:34:17 +04:30
Markus K
53297462d4 Update test_indicators.py 2021-08-03 18:26:17 +02:00
Markus K
f193d33afa Fix formula and add matype. 2021-08-03 18:15:09 +02:00
pyup.io bot
0277b40c9c Update scipy from 1.7.0 to 1.7.1 (#225) 2021-08-03 17:31:11 +02:00
Saleh Mir
748447ce8a get and inject config from the frontend 2021-08-03 19:24:20 +04:30
Saleh Mir
36a849b550 remove inject_local_routes as it's deprecated 2021-07-27 19:15:25 +04:30
Saleh Mir
7f6e18ded4 install and use .env 2021-07-27 19:10:11 +04:30
Markus
c43f3c69ea Pycharm inspection. 2021-07-26 16:44:55 +02:00
Markus
89ac1ce260 Pycharm inspection. 2021-07-26 16:33:25 +02:00
Markus
d1a2738cf4 Add missing dependencies for utils.py 2021-07-26 15:57:39 +02:00
pyup.io bot
561ba38ec3 Update pandas from 1.3.0 to 1.3.1 (#224) 2021-07-26 09:53:19 +02:00
Markus K
47fa228094 Update python-package.yml 2021-07-25 13:21:55 +02:00
Markus K
ccd0a6df55 Update python-package.yml 2021-07-25 13:21:17 +02:00
Markus K
35a3f6ac71 Update python-package.yml 2021-07-25 13:14:23 +02:00
Markus K
a4d3745b6d Update python-package.yml 2021-07-25 13:07:02 +02:00
Markus K
7e6fced118 Update python-package.yml 2021-07-25 13:02:24 +02:00
Markus K
a671f70d45 Update python-package.yml 2021-07-25 12:55:02 +02:00
Markus K
22f01c639b Update python-package.yml 2021-07-25 12:53:26 +02:00
Markus K
65274f7dc0 Update python-package.yml 2021-07-25 12:46:28 +02:00
Markus K
7301e0e0a7 Update python-package.yml 2021-07-25 12:45:13 +02:00
Markus K
b727b8a86e Create python-package.yml 2021-07-25 12:36:20 +02:00
Markus
c8a3ccc1bf Fix 2021-07-25 11:33:40 +02:00
Markus
5fae57fdc9 pyupgrade --py37-plus 2021-07-25 11:27:06 +02:00
Markus
eb6809f8a2 Sourcery optimize 2021-07-25 11:00:50 +02:00
Saleh Mir
5ac7eeb9c5 Update requirements.txt 2021-07-24 20:38:43 +04:30
Saleh Mir
709419c337 refactor handling of available_routes_inputs 2021-07-24 20:38:40 +04:30
Saleh Mir
aceb9764cd handle metrics stream when no trades were executed 2021-07-23 19:50:42 +04:30
Markus
a661f20a63 Add Hurst exponent. 2021-07-23 13:32:05 +02:00
Markus
71ea22916c Merge branch 'master' of https://github.com/jesse-ai/jesse 2021-07-23 13:15:06 +02:00
Saleh Mir
0c081b6f1a implement routes-info endpoint 2021-07-23 13:41:34 +04:30
Markus K
ad353b45d1 Replace Breaker Exception with CandleNotFoundInDatabase 2021-07-23 10:08:41 +02:00
Markus K
33a6ea1d81 Remove old Exceptions MaximumDecimal and Breaker. 2021-07-23 10:07:17 +02:00
Saleh Mir
bda6338632 update error messages for candle loading 2021-07-22 19:33:05 +04:30
Saleh Mir
da963398c0 send paper_mode in geenral_info streams 2021-07-22 19:25:58 +04:30
Saleh Mir
d7ce8c59ce improve exception handling in threads and processes 2021-07-22 17:51:02 +04:30
Saleh Mir
6897cfdfff handle exceptions in threads 2021-07-21 13:52:59 +04:30
Markus K
b6728bee2e Update test_indicators.py 2021-07-19 19:24:40 +02:00
Markus
45cf1eb8fe Merge branch 'master' of https://github.com/jesse-ai/jesse 2021-07-19 19:22:24 +02:00
Markus
1e5238f002 Remove print(). 2021-07-19 19:22:12 +02:00
Markus K
cf4d852088 Fix error related to .size 2021-07-19 19:05:12 +02:00
Markus
cbd54f3179 Merge remote-tracking branch 'origin/master'
# Conflicts:
#	jesse/indicators/supertrend.py
2021-07-19 19:03:17 +02:00
Markus
18854bb103 Use len() instead of .size as it lead to an error. 2021-07-19 19:02:56 +02:00
Yunus S. Dede
8e502d070c Wavetrend indicator (#222)
* Wavetrend indicator

* Wavetrend indicator added

* BTCUSDT 2H test candles added

* Wavetrend indicator test

Co-authored-by: Markus K <16636744+cryptocoinserver@users.noreply.github.com>
2021-07-19 18:01:23 +02:00
Markus
65031d809b Merge remote-tracking branch 'origin/master' 2021-07-19 15:49:18 +02:00
Markus
59fef71cdf Additional check for returned candles. 2021-07-19 15:49:10 +02:00
pyup.io bot
167fa738ff Update numpy from 1.21.0 to 1.21.1 (#223) 2021-07-19 09:39:42 +02:00
Markus
da82aecacd Add Ehlers Predictive Moving Average. 2021-07-18 15:36:20 +02:00
Markus
9e77f8807d Add End Point Moving Average. 2021-07-18 15:17:42 +02:00
Markus
5f342de4af Add Jsa Moving Average. 2021-07-18 14:55:48 +02:00
Markus
2f24de176d Add Cubed Weighted Moving Average . 2021-07-18 14:52:14 +02:00
Markus
2ad1caf06d Add Variable Power Weighted Moving Average. 2021-07-18 14:48:45 +02:00
Markus
fb566531a4 Add Square Root Weighted Moving Average and Squared Weighted Moving Average. 2021-07-18 14:10:11 +02:00
Markus
3255ad65fb Add VLMA. 2021-07-18 12:55:33 +02:00
Markus
4266b796cb Consistency in comments. 2021-07-18 12:38:44 +02:00
Markus
45c27de54a Add MWDX and MAAQ to ma(). 2021-07-18 12:29:47 +02:00
Markus
be1a485252 Add MWDX. 2021-07-18 12:28:03 +02:00
Markus
29c1a9932a Add MAAQ. 2021-07-18 12:22:10 +02:00
Markus
392bc6d933 Rename test_candles for consistency. 2021-07-18 11:43:02 +02:00
Saleh Mir
a06263716d add support for usage of jh.now() outside of modes 2021-07-18 13:14:55 +04:30
Markus
39028eb94c Merge remote-tracking branch 'origin/master' 2021-07-17 16:32:07 +02:00
Markus
a478742634 Add Ulcer Index. 2021-07-17 16:31:59 +02:00
Markus
72afeb9550 Merge remote-tracking branch 'origin/master' 2021-07-17 15:45:25 +02:00
Markus
a03e4873a8 Add Moving Average Bands. 2021-07-17 15:45:17 +02:00
Saleh Mir
4698e58469 broadcast success alert at the end of import-candle 2021-07-16 13:35:05 +04:30
pyup.io bot
188d39fa3a Update pydash from 5.0.1 to 5.0.2 (#221) 2021-07-16 09:53:48 +02:00
Markus
a13db145ea Add Ehlers Distance Coefficient Filter. 2021-07-15 22:45:21 +02:00
Markus
e0b81de17d Add Natural Moving Average. 2021-07-15 22:11:06 +02:00
Markus
769daa62a2 Add Holt-Winter Moving Average and VWAP to ma() 2021-07-15 21:07:30 +02:00
Markus
82d15e0e33 Add Holt-Winter Moving Average. 2021-07-15 21:06:21 +02:00
Markus
c6953a5118 Fix comments. 2021-07-15 21:06:05 +02:00
Markus
a89fe6333f Remove unused import. 2021-07-15 20:54:01 +02:00
Markus
425808703a Add ALMA indicator. 2021-07-15 20:46:48 +02:00
Markus
64d280f012 Use .shape instead of len() 2021-07-15 20:13:07 +02:00
Markus
6024d2d813 Use .size instead of len() 2021-07-15 20:08:06 +02:00
Markus
ceafe9a529 Use .size instead of len() 2021-07-15 19:57:08 +02:00
pyup.io bot
a8d6dce3f4 Update requests from 2.25.1 to 2.26.0 (#219) 2021-07-15 17:22:25 +02:00
pyup.io bot
d95a0ccbee Update ta-lib from 0.4.20 to 0.4.21 (#220) 2021-07-15 17:22:14 +02:00
Saleh Mir
2df8487351 send candle update streams 2021-07-15 14:02:12 +04:30
Saleh Mir
5ca5a6b464 implement get-candles endpoint 2021-07-15 12:51:22 +04:30
Saleh Mir
42396f0771 candles => import-candles 2021-07-14 13:22:08 +04:30
Saleh Mir
b2bee0a357 store candles while live sesison 2021-07-14 13:17:28 +04:30
Saleh Mir
0d3ab626ec remove unused code 2021-07-14 13:17:18 +04:30
Saleh Mir
ec77f93c9b add LiveRequestJson and LiveCancelRequestJson request classes 2021-07-12 17:38:46 +04:30
Saleh Mir
accbb69484 use only one route for both live and paper 2021-07-12 17:38:20 +04:30
Markus
62f21a0e43 Make utility to create unique combinations more flexible. 2021-07-11 13:30:14 +02:00
Markus
1e08c8e219 Merge remote-tracking branch 'origin/master' 2021-07-11 12:51:36 +02:00
Markus
8d619b8eda Add utility to create unique combinations. Useful for parameter optimization of MAs. 2021-07-11 12:51:29 +02:00
Saleh Mir
b33bd577f6 Update multiprocessing.py 2021-07-11 13:39:11 +04:30
Saleh Mir
d63adaeef2 broadcast raised exceptions in a process 2021-07-10 21:07:11 +04:30
Saleh Mir
816ea0ca02 refactor property and method names 2021-07-10 20:06:50 +04:30
Saleh Mir
27a9985559 add DELETE /candles route 2021-07-10 19:40:57 +04:30
Saleh Mir
9201f5208a implement cancel route for backtests 2021-07-10 13:35:40 +04:30
Saleh Mir
1719833102 implement cancel_process 2021-07-10 13:35:28 +04:30
Saleh Mir
c3e4808389 save mode before request id so later we can cancel them 2021-07-09 20:56:53 +04:30
Saleh Mir
3d0005360b refactor candles mode 2021-07-08 13:12:12 +04:30
AlphaNumeric99
7d0cbd9cb0 Typo in utils.py (#218)
Typo in utils.py
2021-07-06 17:20:24 +02:00
Saleh Mir
37a7517c10 bump version 2021-07-06 18:20:55 +04:30
Saleh Mir
6de6cc24a7 Fix store_logs parameter change causing issue with live trade 2021-07-06 18:20:44 +04:30
Saleh Mir
9ce70f3a67 publish data for equity curve chart 2021-07-06 12:56:49 +04:30
Saleh Mir
2f7f177244 redo tests to work with routes refactor 2021-07-05 20:11:28 +04:30
Saleh Mir
73b5ff02fb refactor routes to be parameters of main mode functions 2021-07-05 14:14:34 +04:30
Markus
b4161fcd6a Use better study name in charts.py 2021-07-04 16:34:38 +02:00
Markus
5fa5dc4bc8 Use better study name and actual initial balance in tradingview logs. 2021-07-04 16:28:54 +02:00
Markus K
f620e71f6c Add FAQ link. 2021-07-03 12:22:09 +02:00
pyup.io bot
f4e98ad89e Update pandas from 1.2.5 to 1.3.0 (#217) 2021-07-03 12:17:39 +02:00
Saleh Mir
ff3d8aec8b add support for multiple process using ID 2021-07-02 21:24:14 +04:30
Saleh Mir
36c5a44dc5 round progressbar numbers 2021-06-30 18:09:18 +04:30
Saleh Mir
b7e5ac1ebd short_percentage => shorts_percentage 2021-06-30 18:09:11 +04:30
Markus K
979569f53d Add study_name to page title. 2021-06-28 17:17:23 +02:00
pyup.io bot
a2d7e720b8 Update pydash from 5.0.0 to 5.0.1 (#215) 2021-06-28 14:55:45 +02:00
Saleh Mir
9740179625 Update requirements.txt 2021-06-28 17:23:55 +04:30
Markus K
c4c0c3dbab Update __init__.py 2021-06-27 13:43:49 +02:00
Markus K
3177cc06e2 Update file.py 2021-06-27 13:43:20 +02:00
Markus K
1205d5cae5 Use new study_name in file_name. 2021-06-27 13:39:57 +02:00
Markus K
83ff60a191 Use new study_name in file_name. 2021-06-27 13:39:19 +02:00
Markus K
fbf08dfee8 Add study_name. 2021-06-27 13:38:06 +02:00
Markus K
412564f88f Add start_date and finish_date to file name. 2021-06-27 13:23:36 +02:00
Markus K
ee117e88a0 Pass optimization dates for new file naming. 2021-06-27 13:19:27 +02:00
pyup.io bot
addbe2bf2e Update arrow from 1.1.0 to 1.1.1 (#209) 2021-06-26 15:06:01 +02:00
Saleh Mir
f564786c82 fix parameters issue for POST /backtest 2021-06-26 17:08:15 +04:30
Saleh Mir
dc00eca895 fix CORS issue 2021-06-26 17:07:54 +04:30
pyup.io bot
9baf1ed456 Update pandas from 1.2.4 to 1.2.5 (#208) 2021-06-24 17:58:50 +02:00
pyup.io bot
0dfc45c493 Update numpy from 1.20.3 to 1.21.0 (#207) 2021-06-24 17:58:40 +02:00
Saleh Mir
7a113c8bfb add position type to JSON streams 2021-06-21 22:21:40 +04:30
Saleh Mir
361a6d5368 fix app_mode in live modes changing because of import-candles 2021-06-21 21:47:52 +04:30
Saleh Mir
7313f1d92e ubsubscrine from redis on WS disconnect 2021-06-21 19:08:57 +04:30
pyup.io bot
d8be22db1c Update psycopg2-binary from 2.8.6 to 2.9.1 (#205) 2021-06-21 14:04:09 +02:00
pyup.io bot
7e86dd4326 Update websocket-client from 1.0.1 to 1.1.0 (#200) 2021-06-21 14:03:54 +02:00
pyup.io bot
c06894e776 Update scipy from 1.6.3 to 1.7.0 (#206) 2021-06-21 14:03:28 +02:00
Saleh Mir
023ae30efb use POST request for HTTP endpoints 2021-06-21 14:17:06 +04:30
Saleh Mir
7e87c66b14 Webify import-candles mode via WS 2021-06-21 14:15:39 +04:30
Saleh Mir
34cbd48695 integrate FastAPI
integrate FastAPI

refactor parameters of redis publish functions

implement custom JSON encoder with support for int64

broadcast logs over WS

webify backtest mode

accept parameters for backtests
2021-06-21 13:28:10 +04:30
Saleh Mir
8970b04c4d bump version 2021-06-20 12:51:11 +04:30
Saleh Mir
19f66a67f5 fix the issue of liquidation check for extra_candles 2021-06-19 23:09:57 +04:30
Saleh Mir
0181234352 implement redis service provider 2021-06-19 13:58:43 +04:30
Saleh Mir
bc848d695a create failure service 2021-06-19 13:20:35 +04:30
Saleh Mir
76b7f35e7d add requirements for dashboard 2021-06-18 22:26:11 +04:30
Saleh Mir
b259be3571 implement our own multiprocessing wrapper 2021-06-18 22:25:52 +04:30
Saleh Mir
a85da9dddb add id property to logs 2021-06-18 22:25:26 +04:30
Saleh Mir
956f143373 bump version 2021-06-13 18:04:52 +04:30
Saleh Mir
d011733b47 Merge branch 'plugins' 2021-06-13 18:04:22 +04:30
Saleh Mir
825ab8cfe8 bump version 2021-06-11 22:36:12 +04:30
Saleh Mir
4098460336 refactors for the live trade 2021-06-11 22:36:00 +04:30
Saleh Mir
bc8ef7697d implement candlestick_chart() utility function 2021-06-11 12:05:17 +04:30
Saleh Mir
94f23a37d0 implement a store_candles() function for the research module 2021-06-11 12:05:05 +04:30
Saleh Mir
b493ffbce5 extract store_candles into the "db" service 2021-06-11 12:04:44 +04:30
Saleh Mir
31c510762d fix format 2021-06-11 12:03:37 +04:30
Saleh Mir
0c85d0d19b fix test 2021-06-07 14:11:39 +04:30
Saleh Mir
bba46bb55a bump version 2021-06-07 13:50:56 +04:30
Saleh Mir
1e3c88bb86 don't title the exchange name by default (allow for all uppercase exchange names) 2021-06-06 22:28:18 +04:30
Saleh Mir
db71c8d5a3 add plugins.py to newly created projects 2021-06-06 22:23:25 +04:30
Saleh Mir
94f9a45527 implement driver loading for import-candles from plugins.py 2021-06-06 20:49:23 +04:30
Saleh Mir
5a4d47942d remove endpoint as a required parameter of CandleExchange 2021-06-06 19:26:36 +04:30
Saleh Mir
02c455a530 rename backup_exchange -> backup_exchange_class 2021-06-06 19:23:22 +04:30
Saleh Mir
95b8ca282f refactor: sleep_time => rate_limit_per_second 2021-06-06 19:12:22 +04:30
Saleh Mir
5d3c17df72 fix the order of reported positions 2021-06-06 18:27:09 +04:30
Saleh Mir
7fa4617b23 refactor CandleExchange's architecture 2021-06-05 22:41:47 +04:30
Saleh Mir
80c3c1a270 rename and add comments for new utility functions 2021-06-05 20:26:16 +04:30
Saleh Mir
6cf090b8a4 update newtulipy to a M1 supported version 2021-06-01 12:33:06 +04:30
Saleh Mir
dcce2e9b96 make usage of Numba optional and 2021-06-01 12:32:42 +04:30
Saleh Mir
0dd0a89063 bump version 2021-05-31 18:13:56 +04:30
Saleh Mir
f65763be6d refactor how we handle new candles 2021-05-31 18:13:29 +04:30
Saleh Mir
31eed9c650 remove @cached decorator's uses in Strategy API 2021-05-31 18:13:09 +04:30
Saleh Mir
e5f4e916f8 remove cashed decorator from ExampleStrategy 2021-05-31 18:12:10 +04:30
Saleh Mir
9aacad5773 add comments 2021-05-31 18:11:48 +04:30
Saleh Mir
46941bad3f Merge branch 'master' of github.com:jesse-ai/jesse 2021-05-29 18:44:07 +04:30
Saleh Mir
1c9ef49f68 add z_score and are_cointegrated utils 2021-05-29 18:44:02 +04:30
Saleh Mir
9fdf00c334 Merge pull request #170 from noenfugler/fix_issue_105_charts
Fix issue #105
2021-05-29 18:43:08 +04:30
Saleh Mir
8b84c33e1f fix formatting 2021-05-29 13:39:10 +04:30
Markus
9df3061579 Update requirements. 2021-05-28 10:40:08 +02:00
Markus
35cf807f80 Merge remote-tracking branch 'origin/master' 2021-05-27 15:53:29 +02:00
Markus
b71586c8fc Use new ma indicator in signal_line too. 2021-05-27 15:53:16 +02:00
Saleh Mir
25beeef21f Merge branch 'master' of github.com:jesse-ai/jesse 2021-05-27 13:12:09 +04:30
Saleh Mir
ab98621835 add self.log() method to Strategy API 2021-05-27 13:11:16 +04:30
Markus
57b6f8699a Rename parameter for consistency. 2021-05-26 14:23:53 +02:00
Markus
639928047f Add missing types. 2021-05-26 14:12:35 +02:00
Markus
b0d596d6ec Fix double ma_type. 2021-05-26 12:03:46 +02:00
Markus
516ab94fda Add unit test and change period to match TV. 2021-05-26 11:55:20 +02:00
ob00218
7ee7beacff Add KDJ indicator (#195)
Co-authored-by: Ollie <ob00218@email.com>
2021-05-26 11:44:07 +02:00
Saleh Mir
a57df29245 bump version 2021-05-26 13:10:11 +04:30
Saleh Mir
8079432816 improve _check_for_liquidations 2021-05-24 21:15:21 +04:30
Saleh Mir
417d0fc033 improve display of liquidation price for open positions 2021-05-24 21:15:08 +04:30
Saleh Mir
c6b334cb9d Merge branch 'master' of github.com:jesse-ai/jesse 2021-05-24 21:14:37 +04:30
Saleh Mir
5fb3629aaf format 2021-05-24 20:25:32 +04:30
Saleh Mir
6e0b7463be fix a bug in logger 2021-05-24 20:25:25 +04:30
Saleh Mir
7855d484a9 disable database storage functions in live mode 2021-05-24 20:25:03 +04:30
pyup.io bot
9dbc45f2c8 Update click from 8.0.0 to 8.0.1 (#194) 2021-05-24 17:33:45 +02:00
pyup.io bot
a01c39e548 Update websocket-client from 1.0.0 to 1.0.1 (#196) 2021-05-24 17:33:29 +02:00
Saleh Mir
a723380469 refactor lru_cache 2021-05-24 12:45:28 +04:30
Saleh Mir
e9adb55941 remove unnecessary cachings 2021-05-24 12:35:08 +04:30
Saleh Mir
d349f53a2b add support for the liquidation_price of positions in live mode 2021-05-24 11:11:38 +04:30
Saleh Mir
dba61648b9 TEMP: disable storing of daily balances in live mode 2021-05-24 11:11:19 +04:30
Saleh Mir
f4c377ee40 implement mark_price, funding_rate, next_funding_timestamp properties 2021-05-23 18:03:51 +04:30
Saleh Mir
ae111e5c37 Merge branch 'liquidation' 2021-05-22 21:26:19 +04:30
Saleh Mir
456906d8d5 add mark_price property to the Position class 2021-05-22 21:25:52 +04:30
Saleh Mir
9d3fe34aff limit liquidation in backtest to isolated mode only 2021-05-22 21:04:23 +04:30
Saleh Mir
365293836a limit liquidation_price property to open positions only 2021-05-22 21:04:03 +04:30
Saleh Mir
02d08d817b placeholder for tests for cross mode 2021-05-22 21:03:33 +04:30
Markus
3644894e3a Add Inverse Fisher Transform applied on RSI. 2021-05-18 21:53:42 +02:00
pyup.io bot
89a48db387 Update click from 7.1.2 to 8.0.0 (#189) 2021-05-18 17:19:50 +02:00
pyup.io bot
0f925ecaa0 Update websocket-client from 0.59.0 to 1.0.0 (#192) 2021-05-18 17:19:40 +02:00
pyup.io bot
f849d12184 Update ta-lib from 0.4.19 to 0.4.20 (#193) 2021-05-18 17:19:27 +02:00
Saleh Mir
3f7b083f87 reformat 2021-05-18 13:18:13 +04:30
Saleh Mir
0d6e8999f3 add comments for the method 2021-05-18 12:17:55 +04:30
Saleh Mir
13b2080d21 implement get_downtrend_candles testing utility 2021-05-17 21:53:22 +04:30
Saleh Mir
d2c998fed8 test_liquidation_in_isolated_mode_for_long_trades 2021-05-17 21:53:02 +04:30
Saleh Mir
8252d7d97a don't check for liquidations for spot mode 2021-05-17 21:52:48 +04:30
Saleh Mir
866bf46223 improve liquidation_price 2021-05-17 21:52:29 +04:30
Saleh Mir
7495affd99 remove unused comments 2021-05-17 21:52:18 +04:30
Saleh Mir
a92ba998e9 keep the count of total liquidations in the store 2021-05-17 12:16:00 +04:30
Saleh Mir
bd82aeabeb add support for leverage_mode in single_route_backtest testing utility 2021-05-16 23:19:16 +04:30
Saleh Mir
e52b186c6d add closing_side() helper 2021-05-16 23:18:51 +04:30
Saleh Mir
9bd8f0e8a5 support for liquidation mechanism [part 1] 2021-05-16 23:18:35 +04:30
Saleh Mir
5215d47c1f remove forum 2021-05-16 14:29:43 +04:30
Saleh Mir
4ff3cf4653 improve display of critical errors 2021-05-16 13:00:32 +04:30
Markus
c687e3e917 Merge remote-tracking branch 'origin/master' 2021-05-14 11:38:29 +02:00
Markus
b21c0f3623 Add bandpass. 2021-05-14 11:37:38 +02:00
Soenke
bb02497b02 Fix "sortino" ratio config string (#190) 2021-05-13 12:50:30 +02:00
Markus
23c47b525d Merge remote-tracking branch 'origin/master' 2021-05-12 23:27:09 +02:00
Markus
a7cd6e9310 Add warning for vwma usage with missing volume. 2021-05-12 23:26:58 +02:00
pyup.io bot
22ead50285 Update numpy from 1.20.2 to 1.20.3 (#188) 2021-05-12 10:55:37 +02:00
Markus
564c548457 Add Symmetric Weighted Moving Average 2021-05-10 18:09:52 +02:00
Markus
aa73af816c Add Pascals Weighted Moving Average 2021-05-10 18:01:56 +02:00
Markus
0ec42e0e7f Use f-string. 2021-05-10 14:47:42 +02:00
Markus
136271bb51 Use new ma indicator for matype. 2021-05-10 13:15:41 +02:00
Markus
f7e9dcb915 Add devtype for indicators using STDEV. 2021-05-10 13:00:39 +02:00
Markus
b344ac4e03 Use new ma function in indicators that use matype. 2021-05-10 12:54:12 +02:00
Markus
c79fd92f1e Use new ma function in indicators that use matype. 2021-05-10 12:33:43 +02:00
Markus
fd19681562 Add indicator wrapping (nearly) all MAs which is nice for optimization. Most MAs now work with normal np.array too. 2021-05-10 12:09:51 +02:00
Markus
92897d9408 Add Choppiness Index 2021-05-10 11:31:20 +02:00
Markus
a1f298561f Add Chande Kroll Stop. 2021-05-10 11:21:18 +02:00
Markus
46393c3d31 Add Jurik Moving Average 2021-05-08 14:08:59 +02:00
pyup.io bot
2a76fd6436 Update matplotlib from 3.4.1 to 3.4.2 (#187) 2021-05-08 12:54:47 +02:00
Saleh Mir
ea0649cd71 improve how we detect wrong exchange name in live mode 2021-05-07 18:40:11 +04:30
Saleh Mir
710e7046c5 bump version 2021-05-06 19:40:26 +04:30
Saleh Mir
f5e46ad721 bump version 2021-05-06 19:24:50 +04:30
Saleh Mir
795a357fdf Merge remote-tracking branch 'origin/master' 2021-05-05 22:18:40 +04:30
Saleh Mir
74dfd7d07b improve handling of rounding in live mode to be dynamic based on asset 2021-05-05 22:17:24 +04:30
Markus
976b9cd58b Add Polarized Fractal Efficiency (PFE) 2021-05-05 14:45:38 +02:00
sk
e6f96722c9 add trading_year_days option for 365 days trading for html report (#186) 2021-05-05 14:12:50 +02:00
pyup.io bot
25d12a4bd1 Update websocket-client from 0.58.0 to 0.59.0 (#185)
Co-authored-by: Markus K <16636744+cryptocoinserver@users.noreply.github.com>
2021-05-05 14:11:19 +02:00
pyup.io bot
8ed1b40fad Update quantstats from 0.0.32 to 0.0.34 (#184) 2021-05-05 14:10:38 +02:00
pyup.io bot
ddb13bd60a Update pytest from 6.2.3 to 6.2.4 (#183) 2021-05-05 14:10:26 +02:00
Markus K
14689bb22e Add utils and ta as default imports 2021-05-04 18:21:37 +02:00
Markus K
19790c228d Add utils and ta as default imports in Example. 2021-05-04 18:21:06 +02:00
Saleh Mir
0922edb17f bump version 2021-05-03 23:47:08 +04:30
Saleh Mir
3d453363f9 fix rounding functions use for the live trade 2021-05-03 21:39:11 +04:30
Saleh Mir
1ac19ff900 add missing abstract method 2021-05-03 20:19:55 +04:30
Saleh Mir
8cfc4af14b add _get_precisions abstract method to exchange driver the abstract class 2021-05-03 20:17:00 +04:30
Saleh Mir
3431eeac37 fix index key error 2021-05-03 19:16:14 +04:30
pyup.io bot
53220acab2 Update quantstats from 0.0.30 to 0.0.32 (#182) 2021-05-03 13:30:10 +02:00
Markus
0f0e9c02bc Remove is_paper_trading() as its included in is_live(). 2021-05-02 13:11:32 +02:00
Markus
579cf26d1a Get the precisions from exchange for paper_trading too. Adjust tests for rounding down. Round down in size_to_qty. Make risk_to_qty using precision too. Increase precision of default rounding. Expose self.price_precision and self.qty_precision and fill with exchange precisions if live or paper. 2021-05-02 12:57:27 +02:00
jules goullée
0624f28646 config key with space from env (#179)
* config key with space from env

* os.getenv

* rollback
2021-04-30 18:12:13 +02:00
Markus
803db4b524 Use actual self.symbol to get the precisions. 2021-04-30 17:31:54 +02:00
Markus
977bec14e8 Merge remote-tracking branch 'origin/master' 2021-04-30 17:23:20 +02:00
Markus
01322afd8d Use dynamic precision in rounding of price and qty. 2021-04-30 17:23:11 +02:00
Saleh Mir
829440ffe5 add vars dict property to the Exchange model 2021-04-30 19:15:29 +04:30
Markus
8a25100307 Add round_decimals_down helper and use it in round_qty_for_live_mode. 2021-04-30 16:15:31 +02:00
Markus
89935a5522 Add is_unit_testing config for live unit tests. 2021-04-30 14:50:32 +02:00
Markus
7f5b05c3ce Remove dashy_symbol, as it's not used in the main framework. 2021-04-30 12:53:38 +02:00
Markus
d77ac9e05a Merge remote-tracking branch 'origin/master' 2021-04-29 00:09:17 +02:00
Markus
e3049f0fba Fix minmax indicator. 2021-04-29 00:08:34 +02:00
pyup.io bot
a936bce13c Update arrow from 1.0.3 to 1.1.0 (#181) 2021-04-28 20:29:24 +02:00
Markus
07b4ce0427 Add info about limited spot support. 2021-04-27 14:26:51 +02:00
Markus
78202919bb Merge remote-tracking branch 'origin/master' 2021-04-27 14:21:57 +02:00
Markus
40a8927284 Fix indicator test. 2021-04-27 14:21:45 +02:00
pyup.io bot
463ad64344 Update scipy from 1.6.2 to 1.6.3 (#178) 2021-04-27 12:28:27 +02:00
Markus
4437ab2d52 Merge remote-tracking branch 'origin/master' 2021-04-27 12:28:03 +02:00
Markus
413ae91253 Parameter - naming consistency. 2021-04-27 12:23:59 +02:00
Saleh Mir
6dd09adcff Merge pull request #177 from TheCrazyLex/docker-improvements
docker: Switch to slim image and update python version
2021-04-23 23:42:45 +04:30
Alex Naidis
4d9d5e19a0 docker: Switch to slim image and update python version
- Switch to slim variant of the image
-> Reduces container image size from 1.5GB to 0.9GB (40% reduction)
- Updates Python to 3.9.4
2021-04-22 22:24:57 +02:00
Saleh Mir
1d55c958da link to the discord server instead of the forum 2021-04-20 22:04:16 +04:30
Saleh Mir
0f17f81017 bump version 2021-04-20 20:00:00 +04:30
Saleh Mir
38f5c0325c catch exception to fix quantstat for now 2021-04-20 19:59:45 +04:30
Saleh Mir
993fab396f fix format 2021-04-20 18:58:43 +04:30
Markus
7ae493bdab Add pct_change utils. 2021-04-18 14:31:20 +02:00
Markus
d1bbbec44e Add pct_change utils. 2021-04-18 14:31:12 +02:00
Saleh Mir
68f3764e40 disable collect mode 2021-04-18 14:05:35 +04:30
Saleh Mir
da8d94e053 bump version 2021-04-16 22:19:54 +04:30
Saleh Mir
2dc5b5308f validate that the "live-config.py" file exists 2021-04-16 17:50:08 +04:30
Saleh Mir
192e9e7f89 update config keys format for discord and telegram 2021-04-16 13:16:40 +04:30
pyup.io bot
094d67fd1c Update pandas from 1.2.3 to 1.2.4 (#175) 2021-04-15 21:54:13 +02:00
Markus
1e4455e0a7 Add kurtosis, mean_ad, median_ad, skewness 2021-04-12 14:18:27 +02:00
Markus
4f990b5b5a Add ttm_trend 2021-04-12 13:21:31 +02:00
Markus
53c2147059 Add cached import to example strategies. 2021-04-09 13:55:38 +02:00
Markus
2a457bc364 Merge branch 'pr174' 2021-04-09 13:53:20 +02:00
Markus
a535bd7077 Add cached properties and change to lru_cache 2021-04-09 13:53:01 +02:00
Markus
453639e7b5 Add cached properties and change to lru_cache 2021-04-09 13:39:23 +02:00
Diogo Ribeiro
cd4e4cd633 Cache expensive strategy methods 2021-04-09 09:21:32 +01:00
Markus
6afcb44de9 Make sure only trading routes are considered in benchmark. 2021-04-06 21:30:24 +02:00
Markus
8a2ed4c253 Make sure only trading routes are considered in benchmark. 2021-04-06 21:28:48 +02:00
Markus
615113b9ca Merge remote-tracking branch 'origin/master' 2021-04-06 19:18:04 +02:00
Markus
50a53685fc Add benchmark. 2021-04-06 19:17:56 +02:00
Saleh Mir
58816f40bb Merge branch 'master' of github.com:jesse-ai/jesse 2021-04-05 17:47:15 +04:30
Saleh Mir
993fe84341 implement login command 2021-04-05 17:47:02 +04:30
anton
4791685014 Fix issue #105 unhandled exception when using --charts option and unclosed (short?) position at end of backtest period. 2021-04-05 11:44:17 +10:00
pyup.io bot
217a316862 Update pytest from 6.2.2 to 6.2.3 (#169) 2021-04-04 13:11:27 +02:00
pyup.io bot
0e23d47e8d Update matplotlib from 3.4.0 to 3.4.1 (#167) 2021-03-31 13:30:07 +02:00
Saleh Mir
4a7658813f Merge branch 'master' of github.com:jesse-ai/jesse 2021-03-30 18:32:39 +02:00
Saleh Mir
09d98db314 fix available_margin including reduce_only orders 2021-03-30 18:32:16 +02:00
pyup.io bot
f58511decc Update pydash from 4.9.3 to 5.0.0 (#165) 2021-03-30 15:56:02 +02:00
pyup.io bot
8d3a141d13 Update numpy from 1.20.1 to 1.20.2 (#164) 2021-03-30 15:55:54 +02:00
Saleh Mir
a0e95faa62 Revert "Prevent Import Statement Overhead."
This reverts commit 39dd07080f.
2021-03-28 20:32:29 +02:00
Saleh Mir
96f3f66288 bump version 2021-03-28 20:31:08 +02:00
Saleh Mir
6b3f3a4469 Merge branch 'master' of github.com:jesse-ai/jesse 2021-03-28 20:31:00 +02:00
Saleh Mir
d169ab7a71 catch unsupported exchange driver for the live mode 2021-03-28 20:29:30 +02:00
Saleh Mir
bd660d354c add error() helper 2021-03-28 20:29:09 +02:00
Saleh Mir
d892b142bd remove empty comment 2021-03-28 20:28:58 +02:00
Markus
b281941703 Merge remote-tracking branch 'origin/master' 2021-03-28 16:44:17 +02:00
Markus
96a3536ced Throw exception in import-candles mode if dash is missing. 2021-03-28 16:44:07 +02:00
Markus K
cdb4f7e8b2 Update issue templates 2021-03-28 14:29:00 +02:00
Markus K
f8ab805545 Delete ISSUE_TEMPLATE.md 2021-03-28 14:26:23 +02:00
Markus K
687cdf2005 Update issue templates 2021-03-28 14:26:02 +02:00
Markus
80f8797bc2 Prevent Import Statement Overhead to enhance performance. 2021-03-27 16:12:02 +01:00
Markus
39dd07080f Prevent Import Statement Overhead. 2021-03-27 15:55:57 +01:00
Markus
f5e3956907 Move all_timeframes to be call only when needed. 2021-03-27 15:41:00 +01:00
Markus
8a51434ce3 Replace .format() with f-strings to improve performance. 2021-03-27 15:28:53 +01:00
pyup.io bot
cc3d11c85f Update numba from 0.53.0 to 0.53.1 (#162) 2021-03-27 10:53:21 +01:00
pyup.io bot
f87298025e Update matplotlib from 3.3.4 to 3.4.0 (#161) 2021-03-27 10:53:09 +01:00
pyup.io bot
7087341848 Update quantstats from 0.0.26 to 0.0.30 (#160) 2021-03-27 10:52:56 +01:00
Saleh Mir
8a1bda14c4 Merge pull request #159 from jesse-ai/pyup-update-scipy-1.6.1-to-1.6.2
Update scipy to 1.6.2
2021-03-26 18:24:52 +01:00
Saleh Mir
46891c2c66 improve caching method for self.metrics 2021-03-26 09:14:54 +01:00
Saleh Mir
c04f30e264 cache the value of self.metrics to improve performance 2021-03-25 16:40:37 +01:00
Saleh Mir
67a9354a6a Revert "Merge branch 'master' of github.com:jesse-ai/jesse"
This reverts commit 59817f079d, reversing
changes made to 83a56489d4.
2021-03-25 16:37:04 +01:00
Saleh Mir
59817f079d Merge branch 'master' of github.com:jesse-ai/jesse 2021-03-25 09:13:49 +01:00
Saleh Mir
83a56489d4 load live package from a pip package instead of file 2021-03-25 09:13:19 +01:00
Saleh Mir
aa0e00168a ignore live-config.py 2021-03-25 08:54:06 +01:00
Saleh Mir
7365a5ab62 format file 2021-03-25 08:53:51 +01:00
pyup-bot
2b476ad399 Update scipy from 1.6.1 to 1.6.2 2021-03-25 05:11:50 +01:00
Markus
2acfb70def Extend TestMetrics. 2021-03-24 19:01:29 +01:00
Markus
00c24c078c Fix order of execution related to self.metrics. 2021-03-24 18:46:13 +01:00
Markus
6a4a0340d7 Merge remote-tracking branch 'origin/master' 2021-03-24 18:16:56 +01:00
Markus
ab34471863 Only calculate metrics if they change (on_stop_loss and on_take_profit). 2021-03-24 18:16:48 +01:00
Saleh Mir
aab1b6280d read and inject config files for the live mode from within the Jesse project 2021-03-24 17:26:31 +01:00
Saleh Mir
16b639b359 remove the no-fee flag 2021-03-24 17:01:18 +01:00
Saleh Mir
cec9c68d38 bump version 2021-03-24 14:36:15 +01:00
Markus
21b4438a81 Remove misleading comment. 2021-03-24 13:32:53 +01:00
Markus
c0fcac3eca Remove misleading comment. 2021-03-24 13:31:49 +01:00
Markus
70479fb272 Fix asset errors in Futures and Spot mode. 2021-03-24 13:25:10 +01:00
pyup.io bot
fc87247629 Update peewee from 3.14.3 to 3.14.4 (#151) 2021-03-22 16:02:03 +01:00
Saleh Mir
a6f8843aa9 bump version 2021-03-19 23:18:15 +01:00
Saleh Mir
1d62ae31fc add leverage to position reports 2021-03-19 21:06:27 +01:00
Saleh Mir
0afaec14c5 add leverage property to the Position class 2021-03-19 21:06:11 +01:00
Saleh Mir
9244c76008 implement Discord integration 2021-03-18 19:49:19 +01:00
Saleh Mir
bf2e48f84f ignore html files 2021-03-18 16:30:03 +01:00
Markus K
b7f826c220 Update .travis.yml 2021-03-15 16:59:26 +01:00
Saleh Mir
7480434d42 fix json issue 2021-03-15 09:12:54 +01:00
pyup.io bot
3c47183378 Update numba from 0.53.0rc3 to 0.53.0 (#150) 2021-03-14 18:58:44 +01:00
Saleh Mir
7ffbb7d7b3 bump version 2021-03-12 18:44:12 +01:00
pyup.io bot
7c1237a018 Update peewee from 3.14.2 to 3.14.3 (#149) 2021-03-11 20:44:11 +01:00
Saleh Mir
3be7e35f14 Merge pull request #148 from nicolay-zlobin/quantstats-report
Ability to generate QuantStats' report
2021-03-11 10:27:57 +01:00
Nicolay Zlobin
31d9919f01 Ability to generate QuantStats' report 2021-03-11 12:02:44 +03:00
Markus
9e73156f2c Remove redundant () 2021-03-10 11:42:09 +01:00
Markus
e730db76c2 Format and optimize imports. 2021-03-10 11:37:00 +01:00
Markus
0ece275453 Add Elder Ray Index (ERI) 2021-03-10 10:54:44 +01:00
Markus
94955af8b9 Use helper same_length and slice_candles. 2021-03-10 10:44:31 +01:00
Markus
26ff8371ab Fix wrong np types. 2021-03-10 09:56:17 +01:00
Markus
50bc140835 Merge branch 'master' of https://github.com/jesse-ai/jesse 2021-03-08 18:03:35 +01:00
Saleh Mir
f377083a3d bump version 2021-03-08 17:27:30 +01:00
Saleh Mir
816bdf0aea fix issue where market orders are not detected as reduce_only 2021-03-08 17:08:34 +01:00
Markus
f44a07f3b8 Remove unused import. Fix comment. 2021-03-08 17:07:44 +01:00
Markus
34001e860d Merge remote-tracking branch 'origin/master' 2021-03-08 15:12:25 +01:00
Markus
ff4f2f8ac2 Move np_ffill to helpers and add test. 2021-03-08 15:11:55 +01:00
Saleh Mir
5b7996adda Merge pull request #143 from discohead/futures-leverage-fix
strategy.leverage instead of exchange.futures_leverage
2021-03-08 13:00:36 +01:00
pyup.io bot
21925e5f23 Update arrow from 1.0.2 to 1.0.3 (#147) 2021-03-08 12:40:04 +01:00
Markus
60aaeedda0 Fix wrong np type declarations. 2021-03-07 18:08:35 +01:00
Markus
3d10b5d5a2 Merge remote-tracking branch 'origin/master' 2021-03-06 22:54:58 +01:00
Markus
60238aea43 Fix crossed. Wrong np type declaration in check. 2021-03-06 22:54:34 +01:00
pyup.io bot
e97b88df45 Update peewee from 3.14.1 to 3.14.2 (#145) 2021-03-06 10:50:03 +01:00
pyup.io bot
043666b96f Update numba from 0.53.0rc2 to 0.53.0rc3 (#146) 2021-03-06 10:49:55 +01:00
Markus
cff6b63ae5 Add new timeframes to anchor helper. 2021-03-05 18:14:08 +01:00
Markus
5fd0bf5383 Use only numpy in crossed and add more tests. 2021-03-05 17:53:09 +01:00
Manuel Ebert
f93aebbc81 Only use integers in readable_duration output (#142)
While typed as `int`, the seconds parameter is often passed in as a float in reports, leading to outputs like this:

```python
readable_duration(184722.0, 3)
# 2.0 days, 3.0 hours, 18.0 minutes
```

This is neither pretty nor correct, converting seconds to integer first always gives us the desired output:

```python
readable_duration(184722.0, 3)
# 2 days, 3 hours, 18 minutes
```
2021-03-04 11:29:32 +01:00
pyup.io bot
797a914e4e Update pydash from 4.9.2 to 4.9.3 (#144) 2021-03-04 11:27:22 +01:00
discohead
d995163498 revert test changes 2021-03-03 14:31:27 -08:00
discohead
5c2f0b6c38 conditionally return total_cost with leverage 2021-03-03 14:30:11 -08:00
discohead
328c16ca69 rename to StrategyMock 2021-03-03 14:20:36 -08:00
discohead
ccd231b51c fix tests 2021-03-03 12:30:18 -08:00
discohead
a4daf13513 strategy.leverage instead of exchange.futures_leverage
This seems like the fix for https://github.com/jesse-ai/jesse/issues/122

Also a fixes a bug in the `mode` property of `Position`
2021-03-03 10:59:29 -08:00
pyup.io bot
5f025cc72a Update websocket-client from 0.57.0 to 0.58.0 (#141) 2021-03-03 10:52:31 +01:00
Saleh Mir
d76027fba6 Merge pull request #138 from jesse-ai/pyup-update-pandas-1.2.2-to-1.2.3
Update pandas to 1.2.3
2021-03-02 15:47:09 +01:00
Saleh Mir
dffdf15cfa Merge pull request #139 from jesse-ai/inverse-futures
Inverse futures: import-candle driver only
2021-03-02 15:46:04 +01:00
Saleh Mir
61e679acfd implement driver for importing candle from 'Binance Inverse Futures' 2021-03-02 15:44:31 +01:00
pyup-bot
58df1a1499 Update pandas from 1.2.2 to 1.2.3 2021-03-02 15:38:10 +01:00
Saleh Mir
51dcea96eb remove empty comments 2021-03-02 15:17:28 +01:00
pyup.io bot
0bc6f94b58 Update arrow from 1.0.1 to 1.0.2 (#137) 2021-03-01 11:06:42 +01:00
pyup.io bot
4a01f536df Update arrow from 1.0.0 to 1.0.1 (#136) 2021-02-28 15:28:53 +01:00
pyup.io bot
14e0a73ce4 Update numba from 0.53.0rc1.post1 to 0.53.0rc2 (#135) 2021-02-27 14:35:58 +01:00
pyup.io bot
4820ed2ddd Update arrow from 0.17.0 to 1.0.0 (#134) 2021-02-27 14:35:46 +01:00
Markus
8af63a0f3a Use class_iter to validate timeframe. 2021-02-26 11:49:13 +01:00
Markus
95023593bc Add 45m, 12h, 3D timeframes. 2021-02-24 18:25:54 +01:00
pyup.io bot
b30a5e2de0 Update tabulate from 0.8.8 to 0.8.9 (#132) 2021-02-24 18:07:42 +01:00
pyup.io bot
a2b39c303d Update scipy from 1.6.0 to 1.6.1 (#129) 2021-02-24 18:07:30 +01:00
Jônatas Castro
1df4dbc223 Update rvi.py (#131) 2021-02-21 13:49:09 +01:00
Markus
6454cb2255 Add vwap. 2021-02-20 13:04:16 +01:00
Markus
76d1ee029b Add vwap. 2021-02-19 18:30:50 +01:00
Markus
a3bf9631b6 Merge remote-tracking branch 'origin/master' 2021-02-19 18:04:57 +01:00
Markus
4b0acbdcba Add rvi. 2021-02-19 18:03:24 +01:00
pyup.io bot
b5547b4768 Update tabulate from 0.8.7 to 0.8.8 (#128) 2021-02-19 17:38:45 +01:00
Markus
2795ebaeb5 Use talib for speed. 2021-02-17 21:36:27 +01:00
Markus
6f2e17d05a Merge remote-tracking branch 'origin/master' 2021-02-16 14:15:37 +01:00
Markus
157b161b83 Add stc. 2021-02-16 14:15:25 +01:00
Markus K
3e5b8ae508 Update numba for 3.9 support. 2021-02-16 12:59:14 +01:00
Saleh Mir
a5692e2ab5 Merge branch 'master' of github.com:jesse-ai/jesse 2021-02-16 11:18:42 +01:00
Saleh Mir
b4624fcf96 Send errors to a second telegram bot used only for errors 2021-02-16 11:18:36 +01:00
Markus
51d35e43c3 Add devstop. 2021-02-15 18:39:16 +01:00
Markus
31b4f1dc3c Add rsmk. 2021-02-15 18:33:35 +01:00
Markus
8e79331ffb Fix tests. 2021-02-15 18:24:18 +01:00
Markus
85ef8cf9d5 Add kaufmanstop and safezonestop. 2021-02-15 18:17:47 +01:00
Markus
0b19b16f9e Use numba for speed. 2021-02-15 17:43:26 +01:00
Markus
cc4c3207eb Add high_pass_2_pole and supersmoother_3_pole. Use numba for speed. 2021-02-15 17:18:11 +01:00
Markus
7b0951f083 Use numba to speed up indicators. Add fwma. 2021-02-15 16:58:13 +01:00
Markus
77b71d8164 Use numpy instead of math. 2021-02-15 16:06:06 +01:00
Markus
94b74b834d Use numba to speed up custom indicators. 2021-02-15 15:52:09 +01:00
Markus
e004ff7f4a Use numba to speed up Correlation Cycle. 2021-02-15 14:34:24 +01:00
Markus
0858bbac3b Use numba to speed up CG. 2021-02-15 14:26:48 +01:00
Markus
f4069a14c0 Add numba to requirements 2021-02-15 14:06:52 +01:00
Markus
4b9edda1ec Fix indicator tests. 210 -> 240 2021-02-15 11:18:52 +01:00
Markus
bc303a04e9 Add Kaufman Efficiency indicator & Reformat 2021-02-15 10:43:28 +01:00
Markus
831130c605 Use actual warmup_candles_num in indicators. 2021-02-15 10:17:50 +01:00
pyup.io bot
9eee3e70d7 Update pandas from 1.2.1 to 1.2.2 (#126) 2021-02-10 19:50:16 +01:00
Markus K
4f3bcabfe6 Update .gitignore 2021-02-08 11:19:11 +01:00
Markus K
9c080b4bab Delete test.md 2021-02-08 10:55:08 +01:00
pyup.io bot
0392cac894 Update numpy from 1.20.0 to 1.20.1 (#124) 2021-02-08 10:27:26 +01:00
pyup.io bot
a42fc9d9ab Update peewee from 3.14.0 to 3.14.1 (#125) 2021-02-08 10:27:14 +01:00
Markus K
21b76aa8c8 With typing (#123)
* Add typing.
2021-02-07 20:34:00 +01:00
Saleh Mir
580b91db21 Merge branch 'master' of github.com:jesse-ai/jesse 2021-02-05 11:54:40 +01:00
Saleh Mir
4a5162aaaf fix tests 2021-02-05 11:36:23 +01:00
Saleh Mir
508bd0acde store DailyBalance of different assets into DB in live mode 2021-02-05 11:32:36 +01:00
Saleh Mir
5d93e8b0d6 fix a typo 2021-02-05 11:03:57 +01:00
Markus
46f7ef1973 Add 1W Timeframe 2021-02-05 10:15:24 +01:00
Markus
18d609b08d Merge remote-tracking branch 'origin/master' 2021-02-05 09:55:54 +01:00
Markus
1cfcd8bbb0 Add 1W Timeframe 2021-02-05 09:55:08 +01:00
Saleh Mir
8a17c2fb15 display "strategy name" and "account balance" in CLOSED position message 2021-02-04 18:16:48 +01:00
Saleh Mir
51e48396b0 store Order and CompletedTrade records into database in live mode 2021-02-04 17:51:51 +01:00
Saleh Mir
8dcc0f17a1 Merge branch 'master' of github.com:jesse-ai/jesse 2021-02-03 11:20:10 +01:00
Saleh Mir
bc86d82bb8 improve exception message 2021-02-03 11:19:02 +01:00
Saleh Mir
f1b46a603d create DB table for Order model 2021-02-03 11:18:53 +01:00
Saleh Mir
42bf7baf8d use postgres_ext driver for db to have access to PostgreSQL specific features 2021-02-03 11:18:34 +01:00
Saleh Mir
04fdfb390c create DB table for CompletedTrade model 2021-02-03 09:54:08 +01:00
Saleh Mir
8efc66c13f add trade_id property to Order models 2021-02-03 09:53:20 +01:00
Saleh Mir
689da58d4b add unit test for CompletedTrade model 2021-02-03 09:52:55 +01:00
Saleh Mir
c926772354 add is_valid_uuid() helper function 2021-02-03 09:52:19 +01:00
Markus
7971bafbd3 Add CG Oscillator 2021-02-02 21:55:19 +01:00
Markus
963f6df397 Add Indicator: Chande Forcast Oscillator (CFO) 2021-02-02 21:21:12 +01:00
Saleh Mir
7a0b60fc44 refactor 2021-02-02 16:04:05 +01:00
Saleh Mir
650652ea66 add support for zero_fee to set_up test utility function 2021-02-02 16:03:48 +01:00
Saleh Mir
e00b5c0b1a rename test_trade => test_completed_trade 2021-02-02 15:58:09 +01:00
Saleh Mir
97e750c9d5 bring back frama and sinwma 2021-02-02 15:54:54 +01:00
Saleh Mir
bebdab0348 disable sinwma and frama which very causing tests to fail 2021-02-02 15:38:20 +01:00
Saleh Mir
ea73c4afe9 clean formatting 2021-02-02 15:15:05 +01:00
Saleh Mir
1712c6162e generte new UUID per each Trade object 2021-02-02 15:09:43 +01:00
Saleh Mir
8b4f426b36 Merge branch 'master' of github.com:jesse-ai/jesse 2021-02-02 15:08:32 +01:00
Saleh Mir
1a07afa365 remove empty comments 2021-02-02 15:08:26 +01:00
Saleh Mir
5d6f0d170d remove empty comments 2021-02-01 15:26:18 +01:00
Markus
d270217719 Rever ma_type to matype. 2021-02-01 11:20:28 +01:00
Markus
2e078016b2 Add typing. 2021-02-01 11:18:09 +01:00
Markus
eb53f182ba Refactor for consistency. 2021-02-01 11:03:17 +01:00
Markus
1f4424c6d9 Refactor for consistency. 2021-02-01 10:53:35 +01:00
Markus
109680eaf2 Add Sine Weighted Moving Average (SINWMA) 2021-01-31 21:33:06 +01:00
Markus
0f96bcc507 Fibonacci's Weighted Moving Average (FWMA) 2021-01-31 14:18:39 +01:00
Markus
336875b147 Add missing types. 2021-01-31 13:53:18 +01:00
Markus
3ad0a2bee5 Merge branch 'master' of https://github.com/jesse-ai/jesse 2021-01-31 13:47:43 +01:00
pyup.io bot
07db5c7bd5 Pin numpy to latest version 1.20.0 (#120) 2021-01-31 13:45:46 +01:00
Saleh Mir
ceb0331907 return nan instead None for closed posotion's total_cost value 2021-01-29 14:29:12 +01:00
Saleh Mir
e39bccbe7d rename statistics to metrics 2021-01-29 14:28:45 +01:00
Saleh Mir
6ae50534a3 improve InsufficientMargin's message 2021-01-29 11:32:57 +01:00
Markus
95849bd482 Add missing types. 2021-01-28 21:25:50 +01:00
Saleh Mir
13a7fea49d bump version 2021-01-28 18:50:03 +01:00
Saleh Mir
8bde520ffc add test_statistics_for_trades_without_fee unit test 2021-01-28 16:35:13 +01:00
Saleh Mir
d8dc65282f rename statistics module to metrics 2021-01-28 15:35:28 +01:00
Saleh Mir
4681221bac Merge branch 'leverage' 2021-01-28 15:17:50 +01:00
Saleh Mir
22732f1db8 cleanup 2021-01-28 15:13:40 +01:00
Saleh Mir
df82b85a9b implement wallet_balance and available_margin for the Exchange model and add proper properties for them in the Strategy class 2021-01-28 14:57:48 +01:00
Saleh Mir
52640815ed add types to exchange property of Position class 2021-01-28 14:35:43 +01:00
Saleh Mir
00b3fccb9e Merge pull request #118 from jesse-ai/pyup-update-pytest-6.2.1-to-6.2.2
Update pytest to 6.2.2
2021-01-28 11:55:25 +03:30
Saleh Mir
5d74df9eed add self.leverage property to Strategy 2021-01-27 19:52:27 +03:30
Saleh Mir
f9917d6a86 implement InsufficientMargin validation for futures market 2021-01-27 19:32:32 +03:30
Saleh Mir
60f893d39d use a reduce_only order for closing positons at the end of backtests 2021-01-27 19:31:49 +03:30
Saleh Mir
284d54e823 refactor test_order unit tests 2021-01-27 17:58:01 +03:30
Saleh Mir
a654af4899 add roi, total_cost, and pnl% with support for leverage to CompletedTrade class 2021-01-27 17:38:47 +03:30
Saleh Mir
97b5d5275d improve statistics and reports modules 2021-01-27 17:35:27 +03:30
Saleh Mir
2a0b67d3cf refactor CompletedTrade model 2021-01-27 14:02:46 +03:30
Saleh Mir
e5cc608b55 rename to PNL to pnl and R to r in CompletedTrade objects 2021-01-27 13:30:55 +03:30
Saleh Mir
e15fee22ee add roi and total_cost properties to Position class 2021-01-27 12:51:53 +03:30
Saleh Mir
3219e11c76 refactor + add unit test for position with leverage 2021-01-27 12:51:34 +03:30
Saleh Mir
bd4d50daca don't cash config values when running unit tests 2021-01-27 12:35:19 +03:30
Saleh Mir
bc2efcbab3 improve support for leverage in set_up() helper 2021-01-27 12:34:48 +03:30
Markus
27ce01ce2c Fix rsx indicator test. 2021-01-26 19:42:01 +01:00
Markus
76a1b9bf8b Add rsx indicator. 2021-01-26 19:41:29 +01:00
pyup-bot
76cc671d13 Update pytest from 6.2.1 to 6.2.2 2021-01-26 13:49:53 +01:00
Markus
4826d3f96a Add Market Change metric. 2021-01-25 21:34:54 +01:00
Saleh Mir
dd68a02bc7 implement Position mode + add entry_margin alias 2021-01-25 20:01:36 +03:30
Saleh Mir
b006ef5f4e load leverage config into Exchange model 2021-01-25 19:31:14 +03:30
Saleh Mir
3fbffae598 prepare config file's structure for leverage values 2021-01-25 19:30:40 +03:30
Saleh Mir
d89e46d136 change default fee to taker for Binance Futures 2021-01-25 18:25:50 +03:30
Saleh Mir
981ccf1c71 Merge branch 'leverage' of github.com:jesse-ai/jesse into leverage 2021-01-25 17:03:37 +03:30
Saleh Mir
746a220ef6 remove unnessary code 2021-01-25 16:45:31 +03:30
Saleh Mir
d93c4e2916 remove empty comments 2021-01-25 16:45:24 +03:30
Saleh Mir
edc2817b3d add roi() and total_cost() properties to Position class 2021-01-25 16:45:16 +03:30
Markus
a12033c7a0 Add utils.signal_line 2021-01-23 17:22:18 +01:00
Markus
fd955a432c Make np.diff optional in utils.streaks. 2021-01-23 17:17:29 +01:00
Markus
077201ddcc Fix for max losing and winning streak. 2021-01-23 17:15:12 +01:00
Markus
5034b6b9fa Add current_streak to stats. Use current_streak for max losing and winning streak. 2021-01-23 16:22:49 +01:00
Markus
340ca60ebe Add kelly_criterion to utils. 2021-01-23 14:47:50 +01:00
Markus
c5e8d5d6e6 Move round() to report for better accuracy in self.statistics 2021-01-23 14:43:05 +01:00
Markus
08d0b99a4d Move round() to report for better accuracy in self.statistics 2021-01-23 14:42:36 +01:00
Markus
df11855fe4 Move round() to report for better accuracy in self.statistics 2021-01-23 14:35:11 +01:00
Markus
7afe5eb3c4 Add self.statistics to strategy. 2021-01-23 14:21:35 +01:00
Saleh Mir
cf4b681bb3 raise InvalidConfig exception for wrong exchange type 2021-01-22 14:45:24 +01:00
Saleh Mir
83008ab01e rename ConfigException to InvalidConfig 2021-01-22 14:43:18 +01:00
Saleh Mir
dcce864e6d change default exchange values to "futures" 2021-01-22 14:38:54 +01:00
Saleh Mir
422d813dd8 Refactor Exchange types into Spot and Futures classes 2021-01-22 14:35:08 +01:00
Saleh Mir
fd2812b1b5 Merge pull request #117 from jesse-ai/pyup-update-pandas-1.2.0-to-1.2.1
Update pandas to 1.2.1
2021-01-21 23:25:48 +03:30
pyup-bot
d6b1eb174b Update pandas from 1.2.0 to 1.2.1 2021-01-21 15:44:43 +01:00
Saleh Mir
1af5e7c1b1 Merge pull request #116 from nicolay-zlobin/helperTrades
Ability to get completed trades inside strategy through self.trades
2021-01-21 14:52:08 +01:00
Nicolay Zlobin
b801cc09e1 Ability to get completed trades inside strategy through self.trades 2021-01-21 13:55:31 +03:00
Saleh Mir
9f7b89f770 Merge pull request #115 from julesGoullee/export-json-timeframes
export json add considering_timeframes
2021-01-20 20:41:48 +01:00
Saleh Mir
d60e00a396 Merge pull request #114 from julesGoullee/docker-deployement
split dockerfile for deployement and dockerfileTest
2021-01-20 20:40:05 +01:00
Saleh Mir
6304fdab05 Merge pull request #110 from julesGoullee/db-config-use-env-variable
db config use env variable
2021-01-20 20:39:02 +01:00
Saleh Mir
dc2bc2d917 Merge branch 'master' into leverage 2021-01-20 10:30:56 +01:00
julesGoullee
83f537e099 export json add considering_timeframes 2021-01-19 15:39:39 +04:00
julesGoullee
4019565091 docker build optimization 2021-01-19 15:36:48 +04:00
Saleh Mir
c095b2bb68 Merge branch 'master' of github.com:jesse-ai/jesse 2021-01-18 10:38:27 +01:00
Saleh Mir
9a38ffa7e5 Improve round_qty_for_live_mode to work with minimum order qty on Binance 2021-01-18 10:35:22 +01:00
Saleh Mir
6a229cc3cb implement dd() utility function
very useful for debugging
2021-01-18 10:18:43 +01:00
Markus K
1fd01b7390 Add streaks() utils. 2021-01-16 18:07:38 +01:00
Markus K
f6b34fd3f5 Add missing return types. 2021-01-16 11:24:20 +01:00
Markus K
7466f80730 Add strictly_increasing and strictly_decreasing utils. 2021-01-16 11:22:46 +01:00
julesGoullee
edeaf96e0b end of line 2021-01-15 13:28:30 +04:00
julesGoullee
49e23a036c revert change 2021-01-15 13:26:51 +04:00
julesGoullee
81f51107b9 split dockerfile for deployement and dockerfileTest 2021-01-15 13:24:57 +04:00
julesGoullee
cdb1912e24 helper get_config use env variables 2021-01-15 13:18:19 +04:00
julesGoullee
699a68045b Merge branch 'master' into db-config-use-env-variable 2021-01-14 14:38:05 +04:00
Saleh Mir
18fee9f5d0 Merge pull request #109 from julesGoullee/docker-for-ci
Docker for ci test
2021-01-14 09:54:28 +01:00
Markus K
b8473ae6cb Optimize json csv (#113)
* Added CSV and JSON as option. Return training and testing log seperated.

* Snapshot with optional CSV JSON.

* Optimize JSON add encoding.

* Fix json export.

* Output actual parameters via csv and json.
2021-01-13 16:34:07 +01:00
Gabri
2e91359a81 adding '--skip_confirmation' flag to import-canldes command to avoid … (#111)
* adding '--skip_confirmation' flag to import-canldes command to avoid confirmation on candle duplicates

* changing parameter with dash as name separator

Co-authored-by: Gabriele Guidi <gabriele.guidi@injenia.it>
2021-01-13 16:01:18 +01:00
Markus K
e6e375961a Optimize json csv (#112)
* Added CSV and JSON as option. Return training and testing log seperated.

* Snapshot with optional CSV JSON.

* Optimize JSON add encoding.

* Fix json export.
2021-01-13 15:58:57 +01:00
Saleh Mir
96406afb8d save in-progress code 2021-01-13 15:12:02 +01:00
Saleh Mir
63015ef81e remove empty comments 2021-01-13 15:11:29 +01:00
julesGoullee
89e9e0e097 db config use env variable 2021-01-10 19:45:31 +04:00
julesGoullee
8777ed36f6 docker for ci test 2021-01-10 19:28:27 +04:00
Saleh Mir
49a1ac4671 Add unit test: test_negative_balance_validation_for_spot_market 2021-01-08 14:07:14 +01:00
Saleh Mir
220c545b41 Improve single_route_backtest() to work with both spot and margin 2021-01-08 14:06:59 +01:00
Saleh Mir
1241c04e8e Refactor refactor unit tests to use a separate utils module 2021-01-08 10:39:29 +01:00
Markus K
7798ba1db2 Remove notify again, as its handled in jesse_logger. 2021-01-06 10:48:39 +01:00
Markus K
5b65ea3506 Actually notify. 2021-01-05 11:48:05 +01:00
Saleh Mir
17083487e7 update test_dashless_symbol() 2021-01-02 17:54:02 +01:00
Saleh Mir
d6c2a96270 Merge branch 'master' of github.com:jesse-ai/jesse 2021-01-02 17:51:43 +01:00
Saleh Mir
ef31851558 rename unit test 2021-01-02 17:51:38 +01:00
Saleh Mir
e919a3a68b add dashy_symbo() helper 2021-01-02 17:43:40 +01:00
416 changed files with 17859 additions and 9518 deletions

25
.dockerignore Normal file
View File

@@ -0,0 +1,25 @@
__pycache__
*.pyc
*.pyo
*.pyd
.Python
env
pip-log.txt
pip-delete-this-directory.txt
.tox
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
*.log
.git
*.md
!README*.md
README-secret.md
.travis.yml
Dockerfile
docker-compose.yml
.idea
venv

View File

@@ -1,5 +0,0 @@
<!--
IMPORTANT: Please open an issue ONLY if you find something wrong with the source code. For questions and feedback use Jesse Forum:
https://forum.jesse.trade/
-->

34
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,34 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
<!--
IMPORTANT: Please open an issue ONLY if you find something wrong with the source code. For questions and feedback use Discord (https://jesse.trade/discord). Also make sure to give the documentation (https://docs.jesse.trade/) and FAQ (https://jesse.trade/help) a good read to eliminate the possibility of causing the problem due to wrong usage. Make sure you are using the most recent version `pip show jesse` and updated all requirements `pip install -r https://raw.githubusercontent.com/jesse-ai/jesse/master/requirements.txt`.
-->
**Describe the bug**
A clear and concise description of what the bug is. Include the whole error message / traceback.
**To Reproduce**
Steps to reproduce the behavior:
1. Include your routes.py, config.py (make sure to remove personal information) and if possible your strategy code (if you want to keep it private - contact us on Discord directly).
2. Explain the steps you do that lead to the error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Enviroment (please complete the following information):**
- OS: [e.g. iOS, Windows, Ubuntu]
- Version [use `pip show jesse`]
**Additional context**
Add any other context about the problem here.

View File

@@ -0,0 +1,24 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
<!---
Make sure to check the roadmap (https://docs.jesse.trade/docs/roadmap.html) and the Trello boards linked there whether your idea is already listed and give Jesse's documentation a good read to make sure you don't request something that's already possible. If possible use Discord (https://jesse.trade/discord) to discuss your ideas with the community.
-->
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

11
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "pip" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "daily"

17
.github/stale.yml vendored Normal file
View File

@@ -0,0 +1,17 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

98
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@@ -0,0 +1,98 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '0 0 1 * *'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://git.io/codeql-language-support
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Cache pip
uses: actions/cache@v2
with:
path: ${{ matrix.path }}
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install ta-lib
run: |
if ([ "$RUNNER_OS" = "macOS" ]); then
brew install ta-lib
fi
if ([ "$RUNNER_OS" = "Linux" ]); then
if [ ! -f "$GITHUB_WORKSPACE/ta-lib/src" ]; then wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz -q && tar -xzf ta-lib-0.4.0-src.tar.gz; fi
cd ta-lib/
./configure --prefix=/usr
if [ ! -f "$HOME/ta-lib/src" ]; then make; fi
sudo make install
cd
fi
if ([ "$RUNNER_OS" = "Windows" ]); then
curl -sL http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-msvc.zip -o $GITHUB_WORKSPACE/ta-lib.zip --create-dirs && 7z x $GITHUB_WORKSPACE/ta-lib.zip -o/c/ta-lib && mv /c/ta-lib/ta-lib/* /c/ta-lib/ && rm -rf /c/ta-lib/ta-lib && cd /c/ta-lib/c/make/cdr/win32/msvc && nmake
fi
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
pip install numba
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

97
.github/workflows/python-package.yml vendored Normal file
View File

@@ -0,0 +1,97 @@
# This workflow will install Python dependencies, run tests and lint with a single version of Python
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: Python application
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: ${{matrix.os}}
strategy:
matrix:
# os: [ubuntu-latest, macos-latest, windows-latest]
os: [ubuntu-latest]
include:
- os: ubuntu-latest
path: ~/.cache/pip
#- os: macos-latest
# path: ~/Library/Caches/pip
#- os: windows-latest
# path: ~\AppData\Local\pip\Cache
python-version: [3.8, 3.9, '3.10']
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Cache pip
uses: actions/cache@v2
id: cache
with:
path: ${{ matrix.path }}
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Set up ta-lib dir
if: ${{ runner.os == 'Linux' }}
run: |
mkdir -p $HOME/.local/ta-lib
echo "LD_LIBRARY_PATH=$HOME/.local/ta-lib/lib:$LD_LIBRARY_PATH" >> $GITHUB_ENV
echo "TA_INCLUDE_PATH=$HOME/.local/ta-lib/include" >> $GITHUB_ENV
echo "TA_LIBRARY_PATH=$HOME/.local/ta-lib/lib" >> $GITHUB_ENV
- name: Set up ta-lib cache
if: ${{ runner.os == 'Linux' }}
uses: actions/cache@v2
id: talib-cache
with:
path: |
~/.local/ta-lib/lib
~/.local/ta-lib/include
key: talib-cache-v0.4.0
- name: Install ta-lib mac / windows
run: |
if ([ "$RUNNER_OS" = "macOS" ]); then
brew install ta-lib
fi
if ([ "$RUNNER_OS" = "Windows" ]); then
curl -sL http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-msvc.zip -o $GITHUB_WORKSPACE/ta-lib.zip --create-dirs && 7z x $GITHUB_WORKSPACE/ta-lib.zip -o/c/ta-lib && mv /c/ta-lib/ta-lib/* /c/ta-lib/ && rm -rf /c/ta-lib/ta-lib && cd /c/ta-lib/c/make/cdr/win32/msvc && nmake
fi
- name: Install ta-lib Linux
if: steps.talib-cache.outputs.cache-hit != 'true'
run: |
wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz -q && tar -xzf ta-lib-0.4.0-src.tar.gz
cd ta-lib/
./configure --prefix=$HOME/.local/ta-lib
make
sudo make install
cd
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
if [ ! ${{ matrix.python-version }} = "3.10"]; then pip install numba; fi
pip install -e . -U
# - name: Lint with flake8
# run: |
# stop the build if there are Python syntax errors or undefined names
# flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
# flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
run: |
pip install pytest
pytest

157
.gitignore vendored
View File

@@ -1,20 +1,151 @@
/_pycache_
/.pytest_cache
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# IDE
/.vscode
/jesse.egg-info
/.idea
.DS_Store
/storage/*.key
/storage/*.sqlite
/storage/*.gz
.DS_Store
/.vagrant
*.pyc
/__pycache__
/venv
__pycache__
.vscode
/dist
/build
/*.egg-info
/*.egg
testing-*.py
/storage/full-reports/*.html
/storage/logs/*

View File

@@ -1,5 +1,5 @@
language: python
dist: bionic
dist: focal
cache:
directories:
- $HOME/.cache/pip

28
Dockerfile Normal file
View File

@@ -0,0 +1,28 @@
FROM python:3.9-slim
ENV PYTHONUNBUFFERED 1
RUN apt-get update \
&& apt-get -y install git build-essential libssl-dev \
&& apt-get clean \
&& pip install --upgrade pip
RUN pip3 install Cython numpy
# Prepare environment
RUN mkdir /jesse-docker
WORKDIR /jesse-docker
# Install TA-lib
COPY docker_build_helpers/* /tmp/
RUN cd /tmp && /tmp/install_ta-lib.sh && rm -r /tmp/*ta-lib*
ENV LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
# Install dependencies
COPY requirements.txt /jesse-docker
RUN pip3 install -r requirements.txt
# Build
COPY . /jesse-docker
RUN pip3 install -e .
WORKDIR /home

28
DockerfileTest Normal file
View File

@@ -0,0 +1,28 @@
FROM python:3.9-slim
ENV PYTHONUNBUFFERED 1
RUN apt-get update \
&& apt-get -y install build-essential libssl-dev \
&& apt-get clean \
&& pip install --upgrade pip
RUN pip3 install Cython numpy codecov pytest-cov
# Prepare environment
RUN mkdir /jesse-docker
WORKDIR /jesse-docker
# Install TA-lib
COPY docker_build_helpers/* /tmp/
RUN cd /tmp && /tmp/install_ta-lib.sh && rm -r /tmp/*ta-lib*
ENV LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
# Install dependencies
COPY requirements.txt /jesse-docker
RUN pip3 install -r requirements.txt
# Build
COPY . /jesse-docker
RUN pip3 install -e .
ENTRYPOINT pytest --cov=./ # && codecov

2
MANIFEST.in Normal file
View File

@@ -0,0 +1,2 @@
include jesse/static/*
include jesse/static/**/*

View File

@@ -8,8 +8,8 @@
[![Website](https://img.shields.io/badge/Website-Start%20here!-9cf)](https://jesse.trade)
[![Docs](https://img.shields.io/badge/Docs-Learn%20how!-red)](https://docs.jesse.trade)
[![Docs](https://img.shields.io/discord/771690508413829141)](https://jesse.trade/discord)
[![Forum](https://img.shields.io/badge/Forum-Join%20us!-brightgreen)](https://forum.jesse.trade)
[![FAQ](https://img.shields.io/badge/FAQ-Find%20answers!-yellow)](https://jesse.trade/help)
[![Chat](https://img.shields.io/discord/771690508413829141)](https://jesse.trade/discord)
[![Blog](https://img.shields.io/badge/Blog-Get%20the%20news!-blueviolet)](https://jesse.trade/blog)
---
Jesse is an advanced crypto trading framework which aims to simplify researching and defining trading strategies.
@@ -20,6 +20,11 @@ In fact, it is so simple that in case you already know Python, you can get start
[Here](https://docs.jesse.trade/docs/) you can read more about why Jesse's features.
## Sponsored Promotion
[![TokenBot](https://raw.githubusercontent.com/jesse-ai/jesse/master/assets/TokenBot-Jesse-banner.png)](https://tokenbot.com/?utm_source=github&utm_medium=jesse&utm_campaign=algodevs)
## Getting Started
Head over to the "getting started" section of the [documentation](https://docs.jesse.trade/docs/getting-started). The
documentation is short yet very informative.
@@ -82,9 +87,7 @@ And here are generated charts:
This is the very initial release. There's way more. Subscribe to our mailing list at [jesse.trade](https://jesse.trade) to get the good stuff as soon they're released. Don't worry, We won't send you spam. Pinky promise.
## Community
We've created a [community](http://forum.jesse.trade/) for Jesse users to discuss algo-trading. It's a warm place to share ideas, and help each other out.
**[update]:** We now have a [discord server](https://discord.gg/nztUFbMnF5) to discuss Jesse and trading in general. Make sure to join.
I created a [discord server](https://jesse.trade/discord) for Jesse users to discuss algo-trading. It's a warm place to share ideas, and help each other out.
## How to contribute
Thank you for your interest in contributing to the project. Before starting to work on a PR, please make sure that it isn't under the "in progress" column in our [Github project page](https://github.com/jesse-ai/jesse/projects/2). In case you want to help but don't know what tasks we need help for, checkout the "todo" column.

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

View File

@@ -0,0 +1,17 @@
if [ -z "$1" ]; then
INSTALL_LOC=/usr/local
else
INSTALL_LOC=${1}
fi
echo "Installing to ${INSTALL_LOC}"
if [ ! -f "${INSTALL_LOC}/lib/libta_lib.a" ]; then
tar zxvf ta-lib-0.4.0-src.tar.gz
cd ta-lib \
&& sed -i.bak "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h \
&& ./configure --prefix=${INSTALL_LOC}/ \
&& make \
&& which sudo && sudo make install || make install \
&& echo "export LD_LIBRARY_PATH=/usr/local/lib" >> /root/.bashrc
else
echo "TA-lib already installed, skipping installation"
fi

Binary file not shown.

View File

@@ -1,500 +1,495 @@
import asyncio
import json
import os
import sys
from pydoc import locate
import warnings
from typing import Optional
import click
import pkg_resources
from fastapi import BackgroundTasks, Query, Header
from starlette.websockets import WebSocket, WebSocketDisconnect
from fastapi.responses import JSONResponse, FileResponse
from fastapi.staticfiles import StaticFiles
from jesse.services import auth as authenticator
from jesse.services.redis import async_redis, async_publish, sync_publish
from jesse.services.web import fastapi_app, BacktestRequestJson, ImportCandlesRequestJson, CancelRequestJson, \
LoginRequestJson, ConfigRequestJson, LoginJesseTradeRequestJson, NewStrategyRequestJson, FeedbackRequestJson, \
ReportExceptionRequestJson, OptimizationRequestJson
import uvicorn
from asyncio import Queue
import jesse.helpers as jh
import time
# Hide the "FutureWarning: pandas.util.testing is deprecated." caused by empyrical
import warnings
# to silent stupid pandas warnings
warnings.simplefilter(action='ignore', category=FutureWarning)
# Python version validation.
if jh.python_version() < 3.7:
print(
jh.color(
'Jesse requires Python version above 3.7. Yours is {}'.format(jh.python_version()),
'red'
)
)
# fix directory issue
sys.path.insert(0, os.getcwd())
ls = os.listdir('.')
is_jesse_project = 'strategies' in ls and 'config.py' in ls and 'storage' in ls and 'routes.py' in ls
# variable to know if the live trade plugin is installed
HAS_LIVE_TRADE_PLUGIN = True
try:
import jesse_live
except ModuleNotFoundError:
HAS_LIVE_TRADE_PLUGIN = False
def validate_cwd():
def validate_cwd() -> None:
"""
make sure we're in a Jesse project
"""
if not is_jesse_project:
if not jh.is_jesse_project():
print(
jh.color(
'Current directory is not a Jesse project. You must run commands from the root of a Jesse project.',
'Current directory is not a Jesse project. You must run commands from the root of a Jesse project. Read this page for more info: https://docs.jesse.trade/docs/getting-started/#create-a-new-jesse-project',
'red'
)
)
os._exit(1)
def inject_local_config():
"""
injects config from local config file
"""
local_config = locate('config.config')
from jesse.config import set_config
set_config(local_config)
# print(os.path.dirname(jesse))
JESSE_DIR = os.path.dirname(os.path.realpath(__file__))
def inject_local_routes():
"""
injects routes from local routes folder
"""
local_router = locate('routes')
from jesse.routes import router
router.set_routes(local_router.routes)
router.set_extra_candles(local_router.extra_candles)
# load homepage
@fastapi_app.get("/")
async def index():
return FileResponse(f"{JESSE_DIR}/static/index.html")
# inject local files
if is_jesse_project:
inject_local_config()
inject_local_routes()
@fastapi_app.post("/terminate-all")
async def terminate_all(authorization: Optional[str] = Header(None)):
if not authenticator.is_valid_token(authorization):
return authenticator.unauthorized_response()
from jesse.services.multiprocessing import process_manager
process_manager.flush()
return JSONResponse({'message': 'terminating all tasks...'})
def register_custom_exception_handler():
"""
@fastapi_app.post("/shutdown")
async def shutdown(background_tasks: BackgroundTasks, authorization: Optional[str] = Header(None)):
if not authenticator.is_valid_token(authorization):
return authenticator.unauthorized_response()
:return:
"""
import sys
import threading
import traceback
import logging
from jesse.services import logger as jesse_logger
import click
from jesse import exceptions
background_tasks.add_task(jh.terminate_app)
return JSONResponse({'message': 'Shutting down...'})
log_format = "%(message)s"
os.makedirs('storage/logs', exist_ok=True)
if jh.is_livetrading():
logging.basicConfig(filename='storage/logs/live-trade.txt', level=logging.INFO, filemode='w', format=log_format)
elif jh.is_paper_trading():
logging.basicConfig(filename='storage/logs/paper-trade.txt', level=logging.INFO, filemode='w',
format=log_format)
elif jh.is_collecting_data():
logging.basicConfig(filename='storage/logs/collect.txt', level=logging.INFO, filemode='w',
format=log_format)
elif jh.is_optimizing():
logging.basicConfig(filename='storage/logs/optimize.txt', level=logging.INFO, filemode='w',
format=log_format)
else:
logging.basicConfig(level=logging.INFO)
@fastapi_app.post("/auth")
def auth(json_request: LoginRequestJson):
return authenticator.password_to_token(json_request.password)
# main thread
def handle_exception(exc_type, exc_value, exc_traceback):
"""
:param exc_type:
:param exc_value:
:param exc_traceback:
:return:
"""
if issubclass(exc_type, KeyboardInterrupt):
sys.excepthook(exc_type, exc_value, exc_traceback)
return
@fastapi_app.post("/make-strategy")
def make_strategy(json_request: NewStrategyRequestJson, authorization: Optional[str] = Header(None)) -> JSONResponse:
if not authenticator.is_valid_token(authorization):
return authenticator.unauthorized_response()
# handle Breaking exceptions
if exc_type in [
exceptions.ConfigException, exceptions.RouteNotFound, exceptions.InvalidRoutes,
exceptions.CandleNotFoundInDatabase
]:
click.clear()
print('=' * 30 + ' EXCEPTION TRACEBACK:')
traceback.print_tb(exc_traceback, file=sys.stdout)
print("=" * 73)
print(
'\n',
jh.color('Uncaught Exception:', 'red'),
jh.color('{}: {}'.format(exc_type.__name__, exc_value), 'yellow')
)
return
from jesse.services import strategy_maker
return strategy_maker.generate(json_request.name)
# send notifications if it's a live session
if jh.is_live():
jesse_logger.error(
'{}: {}'.format(exc_type.__name__, exc_value)
@fastapi_app.post("/feedback")
def feedback(json_request: FeedbackRequestJson, authorization: Optional[str] = Header(None)) -> JSONResponse:
if not authenticator.is_valid_token(authorization):
return authenticator.unauthorized_response()
from jesse.services import jesse_trade
return jesse_trade.feedback(json_request.description, json_request.email)
@fastapi_app.post("/report-exception")
def report_exception(json_request: ReportExceptionRequestJson, authorization: Optional[str] = Header(None)) -> JSONResponse:
if not authenticator.is_valid_token(authorization):
return authenticator.unauthorized_response()
from jesse.services import jesse_trade
return jesse_trade.report_exception(
json_request.description,
json_request.traceback,
json_request.mode,
json_request.attach_logs,
json_request.session_id,
json_request.email,
has_live=HAS_LIVE_TRADE_PLUGIN
)
@fastapi_app.post("/get-config")
def get_config(json_request: ConfigRequestJson, authorization: Optional[str] = Header(None)):
if not authenticator.is_valid_token(authorization):
return authenticator.unauthorized_response()
from jesse.modes.data_provider import get_config as gc
return JSONResponse({
'data': gc(json_request.current_config, has_live=HAS_LIVE_TRADE_PLUGIN)
}, status_code=200)
@fastapi_app.post("/update-config")
def update_config(json_request: ConfigRequestJson, authorization: Optional[str] = Header(None)):
if not authenticator.is_valid_token(authorization):
return authenticator.unauthorized_response()
from jesse.modes.data_provider import update_config as uc
uc(json_request.current_config)
return JSONResponse({'message': 'Updated configurations successfully'}, status_code=200)
@fastapi_app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket, token: str = Query(...)):
from jesse.services.multiprocessing import process_manager
from jesse.services.env import ENV_VALUES
if not authenticator.is_valid_token(token):
return
await websocket.accept()
queue = Queue()
ch, = await async_redis.psubscribe(f"{ENV_VALUES['APP_PORT']}:channel:*")
async def echo(q):
while True:
msg = await q.get()
msg = json.loads(msg)
msg['id'] = process_manager.get_client_id(msg['id'])
await websocket.send_json(
msg
)
if jh.is_live() or jh.is_collecting_data():
logging.error("Uncaught Exception:", exc_info=(exc_type, exc_value, exc_traceback))
else:
print('=' * 30 + ' EXCEPTION TRACEBACK:')
traceback.print_tb(exc_traceback, file=sys.stdout)
print("=" * 73)
print(
'\n',
jh.color('Uncaught Exception:', 'red'),
jh.color('{}: {}'.format(exc_type.__name__, exc_value), 'yellow')
)
async def reader(channel, q):
async for ch, message in channel.iter():
# modify id and set the one that the font-end knows
await q.put(message)
if jh.is_paper_trading():
print(
jh.color(
'An uncaught exception was raised. Check the log file at:\n{}'.format(
'storage/logs/paper-trade.txt'
),
'red'
)
)
elif jh.is_livetrading():
print(
jh.color(
'An uncaught exception was raised. Check the log file at:\n{}'.format(
'storage/logs/live-trade.txt'
),
'red'
)
)
elif jh.is_collecting_data():
print(
jh.color(
'An uncaught exception was raised. Check the log file at:\n{}'.format(
'storage/logs/collect.txt'
),
'red'
)
)
asyncio.get_running_loop().create_task(reader(ch, queue))
asyncio.get_running_loop().create_task(echo(queue))
sys.excepthook = handle_exception
# other threads
if jh.python_version() >= 3.8:
def handle_thread_exception(args):
"""
:param args:
:return:
"""
if args.exc_type == SystemExit:
return
# handle Breaking exceptions
if args.exc_type in [
exceptions.ConfigException, exceptions.RouteNotFound, exceptions.InvalidRoutes,
exceptions.CandleNotFoundInDatabase
]:
click.clear()
print('=' * 30 + ' EXCEPTION TRACEBACK:')
traceback.print_tb(args.exc_traceback, file=sys.stdout)
print("=" * 73)
print(
'\n',
jh.color('Uncaught Exception:', 'red'),
jh.color('{}: {}'.format(args.exc_type.__name__, args.exc_value), 'yellow')
)
return
# send notifications if it's a live session
if jh.is_live():
jesse_logger.error(
'{}: {}'.format(args.exc_type.__name__, args.exc_value)
)
if jh.is_live() or jh.is_collecting_data():
logging.error("Uncaught Exception:", exc_info=(args.exc_type, args.exc_value, args.exc_traceback))
else:
print('=' * 30 + ' EXCEPTION TRACEBACK:')
traceback.print_tb(args.exc_traceback, file=sys.stdout)
print("=" * 73)
print(
'\n',
jh.color('Uncaught Exception:', 'red'),
jh.color('{}: {}'.format(args.exc_type.__name__, args.exc_value), 'yellow')
)
if jh.is_paper_trading():
print(
jh.color(
'An uncaught exception was raised. Check the log file at:\n{}'.format(
'storage/logs/paper-trade.txt'
),
'red'
)
)
elif jh.is_livetrading():
print(
jh.color(
'An uncaught exception was raised. Check the log file at:\n{}'.format(
'storage/logs/live-trade.txt'
),
'red'
)
)
elif jh.is_collecting_data():
print(
jh.color(
'An uncaught exception was raised. Check the log file at:\n{}'.format(
'storage/logs/collect.txt'
),
'red'
)
)
threading.excepthook = handle_thread_exception
try:
while True:
# just so WebSocketDisconnect would be raised on connection close
await websocket.receive_text()
except WebSocketDisconnect:
await async_redis.punsubscribe(f"{ENV_VALUES['APP_PORT']}:channel:*")
print('Websocket disconnected')
# create a Click group
@click.group()
@click.version_option(pkg_resources.get_distribution("jesse").version)
def cli():
def cli() -> None:
pass
@cli.command()
@click.argument('exchange', required=True, type=str)
@click.argument('symbol', required=True, type=str)
@click.argument('start_date', required=True, type=str)
def import_candles(exchange, symbol, start_date):
"""
imports historical candles from exchange
"""
@click.option(
'--strict/--no-strict', default=True,
help='Default is the strict mode which will raise an exception if the values for license is not set.'
)
def install_live(strict: bool) -> None:
from jesse.services.installer import install
install(HAS_LIVE_TRADE_PLUGIN, strict)
@cli.command()
def run() -> None:
validate_cwd()
from jesse.config import config
config['app']['trading_mode'] = 'import-candles'
register_custom_exception_handler()
# run all the db migrations
from jesse.services.migrator import run as run_migrations
import peewee
try:
run_migrations()
except peewee.OperationalError:
sleep_seconds = 10
print(f"Database wasn't ready. Sleep for {sleep_seconds} seconds and try again.")
time.sleep(sleep_seconds)
run_migrations()
from jesse.services import db
# read port from .env file, if not found, use default
from jesse.services.env import ENV_VALUES
if 'APP_PORT' in ENV_VALUES:
port = int(ENV_VALUES['APP_PORT'])
else:
port = 9000
# run the main application
uvicorn.run(fastapi_app, host="0.0.0.0", port=port, log_level="info")
@fastapi_app.post('/general-info')
def general_info(authorization: Optional[str] = Header(None)) -> JSONResponse:
if not authenticator.is_valid_token(authorization):
return authenticator.unauthorized_response()
from jesse.modes import data_provider
try:
data = data_provider.get_general_info(has_live=HAS_LIVE_TRADE_PLUGIN)
except Exception as e:
return JSONResponse({
'error': str(e)
}, status_code=500)
return JSONResponse(
data,
status_code=200
)
@fastapi_app.post('/import-candles')
def import_candles(request_json: ImportCandlesRequestJson, authorization: Optional[str] = Header(None)) -> JSONResponse:
from jesse.services.multiprocessing import process_manager
validate_cwd()
if not authenticator.is_valid_token(authorization):
return authenticator.unauthorized_response()
from jesse.modes import import_candles_mode
import_candles_mode.run(exchange, symbol, start_date)
process_manager.add_task(
import_candles_mode.run, 'candles-' + str(request_json.id), request_json.exchange, request_json.symbol,
request_json.start_date, True
)
db.close_connection()
return JSONResponse({'message': 'Started importing candles...'}, status_code=202)
@cli.command()
@click.argument('start_date', required=True, type=str)
@click.argument('finish_date', required=True, type=str)
@click.option('--debug/--no-debug', default=False,
help='Displays logging messages instead of the progressbar. Used for debugging your strategy.')
@click.option('--csv/--no-csv', default=False,
help='Outputs a CSV file of all executed trades on completion.')
@click.option('--json/--no-json', default=False,
help='Outputs a JSON file of all executed trades on completion.')
@click.option('--fee/--no-fee', default=True, help='You can use "--no-fee" as a quick way to set trading fee to zero.')
@click.option('--chart/--no-chart', default=False,
help='Generates charts of daily portfolio balance and assets price change. Useful for a visual comparision of your portfolio against the market.')
@click.option('--tradingview/--no-tradingview', default=False,
help="Generates an output that can be copy-and-pasted into tradingview.com's pine-editor too see the trades in their charts.")
def backtest(start_date, finish_date, debug, csv, json, fee, chart, tradingview):
"""
backtest mode. Enter in "YYYY-MM-DD" "YYYY-MM-DD"
"""
@fastapi_app.delete("/import-candles")
def cancel_import_candles(request_json: CancelRequestJson, authorization: Optional[str] = Header(None)):
from jesse.services.multiprocessing import process_manager
if not authenticator.is_valid_token(authorization):
return authenticator.unauthorized_response()
process_manager.cancel_process('candles-' + request_json.id)
return JSONResponse({'message': f'Candles process with ID of {request_json.id} was requested for termination'}, status_code=202)
@fastapi_app.post("/backtest")
def backtest(request_json: BacktestRequestJson, authorization: Optional[str] = Header(None)):
from jesse.services.multiprocessing import process_manager
if not authenticator.is_valid_token(authorization):
return authenticator.unauthorized_response()
validate_cwd()
from jesse.config import config
config['app']['trading_mode'] = 'backtest'
from jesse.modes.backtest_mode import run as run_backtest
register_custom_exception_handler()
process_manager.add_task(
run_backtest,
'backtest-' + str(request_json.id),
request_json.debug_mode,
request_json.config,
request_json.routes,
request_json.extra_routes,
request_json.start_date,
request_json.finish_date,
None,
request_json.export_chart,
request_json.export_tradingview,
request_json.export_full_reports,
request_json.export_csv,
request_json.export_json
)
from jesse.services import db
from jesse.modes import backtest_mode
from jesse.services.selectors import get_exchange
# debug flag
config['app']['debug_mode'] = debug
# fee flag
if not fee:
for e in config['app']['trading_exchanges']:
config['env']['exchanges'][e]['fee'] = 0
get_exchange(e).fee = 0
backtest_mode.run(start_date, finish_date, chart=chart, tradingview=tradingview, csv=csv, json=json)
db.close_connection()
return JSONResponse({'message': 'Started backtesting...'}, status_code=202)
@cli.command()
@click.argument('start_date', required=True, type=str)
@click.argument('finish_date', required=True, type=str)
@click.argument('optimal_total', required=True, type=int)
@click.option(
'--cpu', default=0, show_default=True,
help='The number of CPU cores that Jesse is allowed to use. If set to 0, it will use as many as is available on your machine.')
@click.option(
'--debug/--no-debug', default=False,
help='Displays detailed logs about the genetics algorithm. Use it if you are interested int he genetics algorithm.'
)
def optimize(start_date, finish_date, optimal_total, cpu, debug):
"""
tunes the hyper-parameters of your strategy
"""
@fastapi_app.post("/optimization")
async def optimization(request_json: OptimizationRequestJson, authorization: Optional[str] = Header(None)):
if not authenticator.is_valid_token(authorization):
return authenticator.unauthorized_response()
from jesse.services.multiprocessing import process_manager
validate_cwd()
from jesse.config import config
config['app']['trading_mode'] = 'optimize'
register_custom_exception_handler()
from jesse.modes.optimize_mode import run as run_optimization
# debug flag
config['app']['debug_mode'] = debug
process_manager.add_task(
run_optimization,
'optimize-' + str(request_json.id),
request_json.debug_mode,
request_json.config,
request_json.routes,
request_json.extra_routes,
request_json.start_date,
request_json.finish_date,
request_json.optimal_total,
request_json.export_csv,
request_json.export_json
)
from jesse.modes.optimize_mode import optimize_mode
# optimize_mode(start_date, finish_date, optimal_total, cpu, csv, json)
optimize_mode(start_date, finish_date, optimal_total, cpu)
return JSONResponse({'message': 'Started optimization...'}, status_code=202)
@cli.command()
@click.argument('name', required=True, type=str)
def make_strategy(name):
@fastapi_app.delete("/optimization")
def cancel_optimization(request_json: CancelRequestJson, authorization: Optional[str] = Header(None)):
if not authenticator.is_valid_token(authorization):
return authenticator.unauthorized_response()
from jesse.services.multiprocessing import process_manager
process_manager.cancel_process('optimize-' + request_json.id)
return JSONResponse({'message': f'Optimization process with ID of {request_json.id} was requested for termination'}, status_code=202)
@fastapi_app.get("/download/{mode}/{file_type}/{session_id}")
def download(mode: str, file_type: str, session_id: str, token: str = Query(...)):
"""
generates a new strategy folder from jesse/strategies/ExampleStrategy
Log files require session_id because there is one log per each session. Except for the optimize mode
"""
validate_cwd()
from jesse.config import config
if not authenticator.is_valid_token(token):
return authenticator.unauthorized_response()
config['app']['trading_mode'] = 'make-strategy'
from jesse.modes import data_provider
register_custom_exception_handler()
from jesse.services import strategy_maker
strategy_maker.generate(name)
return data_provider.download_file(mode, file_type, session_id)
@cli.command()
@click.argument('name', required=True, type=str)
def make_project(name):
@fastapi_app.get("/download/optimize/log")
def download_optimization_log(token: str = Query(...)):
"""
generates a new strategy folder from jesse/strategies/ExampleStrategy
Optimization logs don't have have session ID
"""
from jesse.config import config
if not authenticator.is_valid_token(token):
return authenticator.unauthorized_response()
config['app']['trading_mode'] = 'make-project'
from jesse.modes import data_provider
register_custom_exception_handler()
from jesse.services import project_maker
project_maker.generate(name)
return data_provider.download_file('optimize', 'log')
@cli.command()
@click.option('--dna/--no-dna', default=False, help='Translates DNA into parameters. Used in optimize mode only')
def routes(dna):
"""
lists all routes
"""
validate_cwd()
from jesse.config import config
@fastapi_app.delete("/backtest")
def cancel_backtest(request_json: CancelRequestJson, authorization: Optional[str] = Header(None)):
if not authenticator.is_valid_token(authorization):
return authenticator.unauthorized_response()
config['app']['trading_mode'] = 'routes'
from jesse.services.multiprocessing import process_manager
register_custom_exception_handler()
process_manager.cancel_process('backtest-' + request_json.id)
from jesse.modes import routes_mode
routes_mode.run(dna)
return JSONResponse({'message': f'Backtest process with ID of {request_json.id} was requested for termination'}, status_code=202)
if 'plugins' in ls:
@cli.command()
def collect():
"""
fetches streamed market data such as tickers, trades, and orderbook from
the WS connection and stores them into the database for later research.
"""
@fastapi_app.on_event("shutdown")
def shutdown_event():
from jesse.services.db import database
database.close_connection()
if HAS_LIVE_TRADE_PLUGIN:
from jesse.services.web import fastapi_app, LiveRequestJson, LiveCancelRequestJson, GetCandlesRequestJson, \
GetLogsRequestJson, GetOrdersRequestJson
from jesse.services import auth as authenticator
@fastapi_app.post("/live")
def live(request_json: LiveRequestJson, authorization: Optional[str] = Header(None)) -> JSONResponse:
if not authenticator.is_valid_token(authorization):
return authenticator.unauthorized_response()
from jesse import validate_cwd
# dev_mode is used only by developers so it doesn't have to be a supported parameter
dev_mode: bool = False
validate_cwd()
# set trading mode
from jesse.config import config
config['app']['trading_mode'] = 'collect'
register_custom_exception_handler()
from plugins.live.collect_mode import run
run()
@cli.command()
@click.option('--testdrive/--no-testdrive', default=False)
@click.option('--debug/--no-debug', default=False)
@click.option('--dev/--no-dev', default=False)
@click.option('--fee/--no-fee', default=True)
def live(testdrive, debug, dev, fee):
"""
trades in real-time on exchange with REAL money
"""
validate_cwd()
# set trading mode
from jesse.config import config
config['app']['trading_mode'] = 'livetrade'
config['app']['is_test_driving'] = testdrive
register_custom_exception_handler()
# debug flag
config['app']['debug_mode'] = debug
from plugins.live import init
from jesse.services.selectors import get_exchange
# fee flag
if not fee:
for e in config['app']['trading_exchanges']:
config['env']['exchanges'][e]['fee'] = 0
get_exchange(e).fee = 0
# inject live config
init(config)
# execute live session
from plugins.live.live_mode import run
run(dev)
from jesse_live import live_mode
from jesse.services.multiprocessing import process_manager
trading_mode = 'livetrade' if request_json.paper_mode is False else 'papertrade'
process_manager.add_task(
live_mode.run,
f'{trading_mode}-' + str(request_json.id),
request_json.debug_mode,
dev_mode,
request_json.config,
request_json.routes,
request_json.extra_routes,
trading_mode,
)
mode = 'live' if request_json.paper_mode is False else 'paper'
return JSONResponse({'message': f"Started {mode} trading..."}, status_code=202)
@cli.command()
@click.option('--debug/--no-debug', default=False)
@click.option('--dev/--no-dev', default=False)
@click.option('--fee/--no-fee', default=True)
def paper(debug, dev, fee):
"""
trades in real-time on exchange with PAPER money
"""
@fastapi_app.delete("/live")
def cancel_backtest(request_json: LiveCancelRequestJson, authorization: Optional[str] = Header(None)):
if not authenticator.is_valid_token(authorization):
return authenticator.unauthorized_response()
from jesse.services.multiprocessing import process_manager
trading_mode = 'livetrade' if request_json.paper_mode is False else 'papertrade'
process_manager.cancel_process(f'{trading_mode}-' + request_json.id)
return JSONResponse({'message': f'Live process with ID of {request_json.id} terminated.'}, status_code=200)
@fastapi_app.post('/get-candles')
def get_candles(json_request: GetCandlesRequestJson, authorization: Optional[str] = Header(None)) -> JSONResponse:
if not authenticator.is_valid_token(authorization):
return authenticator.unauthorized_response()
from jesse import validate_cwd
validate_cwd()
# set trading mode
from jesse.config import config
config['app']['trading_mode'] = 'papertrade'
from jesse.modes.data_provider import get_candles as gc
register_custom_exception_handler()
arr = gc(json_request.exchange, json_request.symbol, json_request.timeframe)
# debug flag
config['app']['debug_mode'] = debug
return JSONResponse({
'id': json_request.id,
'data': arr
}, status_code=200)
from plugins.live import init
from jesse.services.selectors import get_exchange
# fee flag
if not fee:
for e in config['app']['trading_exchanges']:
config['env']['exchanges'][e]['fee'] = 0
get_exchange(e).fee = 0
@fastapi_app.post('/get-logs')
def get_logs(json_request: GetLogsRequestJson, authorization: Optional[str] = Header(None)) -> JSONResponse:
if not authenticator.is_valid_token(authorization):
return authenticator.unauthorized_response()
# inject live config
init(config)
from jesse_live.services.data_provider import get_logs as gl
# execute live session
from plugins.live.live_mode import run
run(dev)
arr = gl(json_request.session_id, json_request.type)
return JSONResponse({
'id': json_request.id,
'data': arr
}, status_code=200)
@fastapi_app.post('/get-orders')
def get_orders(json_request: GetOrdersRequestJson, authorization: Optional[str] = Header(None)) -> JSONResponse:
if not authenticator.is_valid_token(authorization):
return authenticator.unauthorized_response()
from jesse_live.services.data_provider import get_orders as go
arr = go(json_request.session_id)
return JSONResponse({
'id': json_request.id,
'data': arr
}, status_code=200)
# Mount static files.Must be loaded at the end to prevent overlapping with API endpoints
fastapi_app.mount("/", StaticFiles(directory=f"{JESSE_DIR}/static"), name="static")

View File

@@ -1,14 +1,9 @@
import jesse.helpers as jh
config = {
# these values are related to the user's environment
'env': {
'databases': {
'postgres_host': '127.0.0.1',
'postgres_name': 'jesse_db',
'postgres_port': 5432,
'postgres_username': 'jesse_user',
'postgres_password': 'password',
},
'caching': {
'driver': 'pickle'
},
@@ -30,88 +25,177 @@ config = {
'Sandbox': {
'fee': 0,
'type': 'spot',
# used only in margin trading
# used only in futures trading
'settlement_currency': 'USDT',
# accepted values are: 'cross' and 'isolated'
'futures_leverage_mode': 'cross',
# 1x, 2x, 10x, 50x, etc. Enter as integers
'futures_leverage': 1,
'assets': [
{'asset': 'USDT', 'balance': 10000},
{'asset': 'USDT', 'balance': 10_000},
{'asset': 'BTC', 'balance': 0},
],
},
'Bybit Perpetual': {
'fee': 0.00075,
# backtest mode only: accepted are 'spot' and 'futures'
# 'spot' support is currently very limited - you can use 'futures' with leverage 1 for now
'type': 'futures',
# futures mode only
'settlement_currency': 'USDT',
# accepted values are: 'cross' and 'isolated'
'futures_leverage_mode': 'cross',
# 1x, 2x, 10x, 50x, etc. Enter as integers
'futures_leverage': 1,
'assets': [
{'asset': 'USDT', 'balance': 10_000},
],
},
'Testnet Bybit Perpetual': {
'fee': 0.00075,
# backtest mode only: accepted are 'spot' and 'futures'
# 'spot' support is currently very limited - you can use 'futures' with leverage 1 for now
'type': 'futures',
# futures mode only
'settlement_currency': 'USDT',
# accepted values are: 'cross' and 'isolated'
'futures_leverage_mode': 'cross',
# 1x, 2x, 10x, 50x, etc. Enter as integers
'futures_leverage': 1,
'assets': [
{'asset': 'USDT', 'balance': 10_000},
],
},
# https://ftx.com/markets/future
'FTX Futures': {
'fee': 0.0006,
# backtest mode only: accepted are 'spot' and 'futures'
# 'spot' support is currently very limited - you can use 'futures' with leverage 1 for now
'type': 'futures',
# futures mode only
'settlement_currency': 'USD',
# accepted values are: 'cross' and 'isolated'
'futures_leverage_mode': 'cross',
# 1x, 2x, 10x, 20x, etc. Enter as integers
'futures_leverage': 1,
'assets': [
{'asset': 'USD', 'balance': 10_000},
],
},
# https://www.bitfinex.com
'Bitfinex': {
'type': 'margin',
# used only in margin trading
'settlement_currency': 'USD',
'fee': 0.002,
# backtest mode only: accepted are 'spot' and 'futures'
'type': 'futures',
# futures mode only
'settlement_currency': 'USD',
# accepted values are: 'cross' and 'isolated'
'futures_leverage_mode': 'cross',
# 1x, 2x, 10x, 50x, etc. Enter as integers
'futures_leverage': 1,
'assets': [
{'asset': 'USDT', 'balance': 10000},
{'asset': 'USD', 'balance': 10000},
{'asset': 'USDT', 'balance': 10_000},
{'asset': 'USD', 'balance': 10_000},
{'asset': 'BTC', 'balance': 0},
],
},
# https://www.binance.com
'Binance': {
'type': 'spot',
# used only in margin trading
'settlement_currency': 'USDT',
'fee': 0.001,
# backtest mode only: accepted are 'spot' and 'futures'
'type': 'futures',
# futures mode only
'settlement_currency': 'USDT',
# accepted values are: 'cross' and 'isolated'
'futures_leverage_mode': 'cross',
# 1x, 2x, 10x, 50x, etc. Enter as integers
'futures_leverage': 1,
'assets': [
{'asset': 'USDT', 'balance': 10000},
{'asset': 'USDT', 'balance': 10_000},
{'asset': 'BTC', 'balance': 0},
],
},
# https://www.binance.com
'Binance Futures': {
'type': 'margin',
# used only in margin trading
'fee': 0.0004,
# backtest mode only: accepted are 'spot' and 'futures'
'type': 'futures',
# futures mode only
'settlement_currency': 'USDT',
'fee': 0.0002,
# accepted values are: 'cross' and 'isolated'
'futures_leverage_mode': 'cross',
# 1x, 2x, 10x, 50x, etc. Enter as integers
'futures_leverage': 1,
'assets': [
{'asset': 'USDT', 'balance': 10000},
{'asset': 'USDT', 'balance': 10_000},
],
},
# https://testnet.binancefuture.com
'Testnet Binance Futures': {
'type': 'margin',
# used only in margin trading
'fee': 0.0004,
# backtest mode only: accepted are 'spot' and 'futures'
'type': 'futures',
# futures mode only
'settlement_currency': 'USDT',
'fee': 0.0002,
# accepted values are: 'cross' and 'isolated'
'futures_leverage_mode': 'cross',
# 1x, 2x, 10x, 50x, etc. Enter as integers
'futures_leverage': 1,
'assets': [
{'asset': 'USDT', 'balance': 10000},
{'asset': 'USDT', 'balance': 10_000},
],
},
# https://pro.coinbase.com
'Coinbase': {
'type': 'spot',
# used only in margin trading
'settlement_currency': 'USDT',
'fee': 0.005,
# backtest mode only: accepted are 'spot' and 'futures'
'type': 'futures',
# futures mode only
'settlement_currency': 'USD',
# accepted values are: 'cross' and 'isolated'
'futures_leverage_mode': 'cross',
# 1x, 2x, 10x, 50x, etc. Enter as integers
'futures_leverage': 1,
'assets': [
{'asset': 'USDT', 'balance': 10000},
{'asset': 'USDT', 'balance': 10_000},
{'asset': 'USD', 'balance': 10_000},
{'asset': 'BTC', 'balance': 0},
],
},
},
# changes the metrics output of the backtest
'metrics': {
'sharpe_ratio': True,
'calmar_ratio': False,
'sortino_ratio': False,
'omega_ratio': False,
'winning_streak': False,
'losing_streak': False,
'largest_losing_trade': False,
'largest_winning_trade': False,
'total_winning_trades': False,
'total_losing_trades': False,
},
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Optimize mode
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
@@ -119,7 +203,7 @@ config = {
# Below configurations are related to the optimize mode
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
'optimization': {
# sharpe, calmar, sortino, omega
# sharpe, calmar, sortino, omega, serenity, smart sharpe, smart sortino
'ratio': 'sharpe',
},
@@ -131,7 +215,7 @@ config = {
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
'data': {
# The minimum number of warmup candles that is loaded before each session.
'warmup_candles_num': 210,
'warmup_candles_num': 240,
}
},
@@ -165,28 +249,73 @@ config = {
# this would enable many console.log()s in the code, which are helpful for debugging.
'debug_mode': False,
# this is only used for the live unit tests
'is_unit_testing': False,
},
}
backup_config = config.copy()
def set_config(c):
def set_config(conf: dict) -> None:
global config
config['env'] = c
# add sandbox because it isn't in the local config file
config['env']['exchanges']['Sandbox'] = {
'type': 'spot',
# used only in margin trading
'settlement_currency': 'USDT',
'fee': 0,
'assets': [
{'asset': 'USDT', 'balance': 10000},
{'asset': 'BTC', 'balance': 0},
],
}
# optimization mode only
if jh.is_optimizing():
# ratio
config['env']['optimization']['ratio'] = conf['ratio']
# exchange info (only one because the optimize mode supports only one trading route at the moment)
config['env']['optimization']['exchange'] = conf['exchange']
# warm_up_candles
config['env']['optimization']['warmup_candles_num'] = int(conf['warm_up_candles'])
# backtest and live
if jh.is_backtesting() or jh.is_live():
# warm_up_candles
config['env']['data']['warmup_candles_num'] = int(conf['warm_up_candles'])
# logs
config['env']['logging'] = conf['logging']
# exchanges
for key, e in conf['exchanges'].items():
config['env']['exchanges'][e['name']] = {
'fee': float(e['fee']),
'type': 'futures',
# used only in futures trading
# 'settlement_currency': 'USDT',
'settlement_currency': jh.get_settlement_currency_from_exchange(e['name']),
# accepted values are: 'cross' and 'isolated'
'futures_leverage_mode': e['futures_leverage_mode'],
# 1x, 2x, 10x, 50x, etc. Enter as integers
'futures_leverage': int(e['futures_leverage']),
'assets': [
{'asset': 'USDT', 'balance': float(e['balance'])},
],
}
# live mode only
if jh.is_live():
config['env']['notifications'] = conf['notifications']
# TODO: must become a config value later when we go after multi account support?
config['env']['identifier'] = 'main'
# # add sandbox because it isn't in the local config file but it is needed since we might have replaced it
# config['env']['exchanges']['Sandbox'] = {
# 'type': 'spot',
# # used only in futures trading
# 'settlement_currency': 'USDT',
# 'fee': 0,
# 'futures_leverage_mode': 'cross',
# 'futures_leverage': 1,
# 'assets': [
# {'asset': 'USDT', 'balance': 10_000},
# {'asset': 'BTC', 'balance': 0},
# ],
# }
def reset_config():
def reset_config() -> None:
global config
config = backup_config.copy()
backup_config = config.copy()

View File

@@ -12,7 +12,9 @@ class order_statuses:
ACTIVE = 'ACTIVE'
CANCELED = 'CANCELED'
EXECUTED = 'EXECUTED'
PARTIALLY_FILLED = 'PARTIALLY FILLED'
QUEUED = 'QUEUED'
LIQUIDATED = 'LIQUIDATED'
class timeframes:
@@ -21,12 +23,14 @@ class timeframes:
MINUTE_5 = '5m'
MINUTE_15 = '15m'
MINUTE_30 = '30m'
MINUTE_45 = '45m'
HOUR_1 = '1h'
HOUR_2 = '2h'
HOUR_3 = '3h'
HOUR_4 = '4h'
HOUR_6 = '6h'
HOUR_8 = '8h'
HOUR_12 = '12h'
DAY_1 = '1D'
@@ -38,21 +42,6 @@ class colors:
BLACK = 'black'
class order_roles:
OPEN_POSITION = 'OPEN POSITION'
CLOSE_POSITION = 'CLOSE POSITION'
INCREASE_POSITION = 'INCREASE POSITION'
REDUCE_POSITION = 'REDUCE POSITION'
class order_flags:
OCO = 'OCO'
POST_ONLY = 'PostOnly'
CLOSE = 'Close'
HIDDEN = 'Hidden'
REDUCE_ONLY = 'ReduceOnly'
class order_types:
MARKET = 'MARKET'
LIMIT = 'LIMIT'

View File

@@ -18,10 +18,6 @@ class InvalidStrategy(Exception):
pass
class Breaker(Exception):
pass
class CandleNotFoundInDatabase(Exception):
pass
@@ -34,10 +30,6 @@ class SymbolNotFound(Exception):
pass
class MaximumDecimal(Exception):
pass
class RouteNotFound(Exception):
pass
@@ -54,16 +46,29 @@ class ExchangeNotResponding(Exception):
pass
class ExchangeRejectedOrder(Exception):
pass
class InvalidShape(Exception):
pass
class ConfigException(Exception):
class InvalidConfig(Exception):
pass
class InvalidTimeframe(Exception):
pass
class NegativeBalance(Exception):
pass
class InsufficientMargin(Exception):
pass
class Termination(Exception):
pass

View File

@@ -1,5 +1,6 @@
from abc import ABC, abstractmethod
from typing import Union
from jesse.models import Order
class Exchange(ABC):
"""
@@ -7,65 +8,25 @@ class Exchange(ABC):
"""
@abstractmethod
def market_order(self, symbol, qty, current_price, side, role, flags):
"""
:param symbol:
:param qty:
:param current_price:
:param side:
:param role:
:param flags:
"""
def market_order(self, symbol: str, qty: float, current_price: float, side: str, reduce_only: bool) -> Order:
pass
@abstractmethod
def limit_order(self, symbol, qty, price, side, role, flags):
"""
:param symbol:
:param qty:
:param price:
:param side:
:param role:
:param flags:
"""
def limit_order(self, symbol: str, qty: float, price: float, side: str, reduce_only: bool) -> Order:
pass
@abstractmethod
def stop_order(self, symbol, qty, price, side, role, flags):
"""
:param symbol:
:param qty:
:param price:
:param side:
:param role:
:param flags:
"""
def stop_order(self, symbol: str, qty: float, price: float, side: str, reduce_only: bool) -> Order:
pass
@abstractmethod
def cancel_all_orders(self, symbol):
"""
:param symbol:
"""
def cancel_all_orders(self, symbol: str) -> None:
pass
@abstractmethod
def cancel_order(self, symbol, order_id):
"""
:param symbol:
:param order_id:
"""
def cancel_order(self, symbol: str, order_id: str) -> None:
pass
@abstractmethod
def get_exec_inst(self, flags):
"""
:param flags:
"""
def _fetch_precisions(self) -> None:
pass

View File

@@ -3,37 +3,24 @@ from jesse.enums import order_types
from jesse.exchanges.exchange import Exchange
from jesse.models import Order
from jesse.store import store
from typing import Union
class Sandbox(Exchange):
"""
"""
def __init__(self, name='Sandbox'):
super().__init__()
self.name = name
def market_order(self, symbol, qty, current_price, side, role, flags):
"""
:param symbol:
:param qty:
:param current_price:
:param side:
:param role:
:param flags:
:return:
"""
def market_order(self, symbol: str, qty: float, current_price: float, side: str, reduce_only: bool) -> Order:
order = Order({
'id': jh.generate_unique_id(),
'symbol': symbol,
'exchange': self.name,
'side': side,
'type': order_types.MARKET,
'flag': self.get_exec_inst(flags),
'reduce_only': reduce_only,
'qty': jh.prepare_qty(qty, side),
'price': current_price,
'role': role
})
store.orders.add_order(order)
@@ -42,65 +29,39 @@ class Sandbox(Exchange):
return order
def limit_order(self, symbol, qty, price, side, role, flags):
"""
:param symbol:
:param qty:
:param price:
:param side:
:param role:
:param flags:
:return:
"""
def limit_order(self, symbol: str, qty: float, price: float, side: str, reduce_only: bool) -> Order:
order = Order({
'id': jh.generate_unique_id(),
'symbol': symbol,
'exchange': self.name,
'side': side,
'type': order_types.LIMIT,
'flag': self.get_exec_inst(flags),
'reduce_only': reduce_only,
'qty': jh.prepare_qty(qty, side),
'price': price,
'role': role
})
store.orders.add_order(order)
return order
def stop_order(self, symbol, qty, price, side, role, flags):
"""
:param symbol:
:param qty:
:param price:
:param side:
:param role:
:param flags:
:return:
"""
def stop_order(self, symbol: str, qty: float, price: float, side: str, reduce_only: bool) -> Order:
order = Order({
'id': jh.generate_unique_id(),
'symbol': symbol,
'exchange': self.name,
'side': side,
'type': order_types.STOP,
'flag': self.get_exec_inst(flags),
'reduce_only': reduce_only,
'qty': jh.prepare_qty(qty, side),
'price': price,
'role': role
})
store.orders.add_order(order)
return order
def cancel_all_orders(self, symbol):
"""
:param symbol:
"""
def cancel_all_orders(self, symbol: str) -> None:
orders = filter(lambda o: o.is_new,
store.orders.get_orders(self.name, symbol))
@@ -108,22 +69,10 @@ class Sandbox(Exchange):
o.cancel()
if not jh.is_unit_testing():
store.orders.storage['{}-{}'.format(self.name, symbol)].clear()
store.orders.storage[f'{self.name}-{symbol}'].clear()
def cancel_order(self, symbol, order_id):
"""
:param symbol:
:param order_id:
"""
def cancel_order(self, symbol: str, order_id: str) -> None:
store.orders.get_order_by_id(self.name, symbol, order_id).cancel()
def get_exec_inst(self, flags):
"""
:param flags:
:return:
"""
if flags:
return flags[0]
return None
def _fetch_precisions(self) -> None:
pass

View File

@@ -1,4 +1,4 @@
from .candle_factory import fake_candle
from .candle_factory import fake_range_candle
from .candle_factory import fake_range_candle_from_range_prices
from .candle_factory import range_candles
from .candle_factory import candles_from_close_prices
from .order_factory import fake_order

View File

@@ -1,8 +1,10 @@
from random import randint
from typing import Union
import numpy as np
first_timestamp = 1552309186171
# 2021-01-01T00:00:00+00:00
first_timestamp = 1609459080000
open_price = randint(40, 100)
close_price = randint(open_price, 110) if randint(0, 1) else randint(
30, open_price)
@@ -12,11 +14,9 @@ min_price = min(open_price, close_price)
low_price = min_price if randint(0, 1) else randint(min_price, min_price + 10)
def fake_range_candle(count) -> np.ndarray:
def range_candles(count: int) -> np.ndarray:
"""
:param count:
:return:
Generates a range of candles with random values.
"""
fake_candle(reset=True)
arr = np.zeros((count, 6))
@@ -25,11 +25,10 @@ def fake_range_candle(count) -> np.ndarray:
return arr
def fake_range_candle_from_range_prices(prices) -> np.ndarray:
def candles_from_close_prices(prices: Union[list, range]) -> np.ndarray:
"""
:param prices:
:return:
Generates a range of candles from a list of close prices.
The first candle has the timestamp of "2021-01-01T00:00:00+00:00"
"""
fake_candle(reset=True)
global first_timestamp
@@ -55,13 +54,7 @@ def fake_range_candle_from_range_prices(prices) -> np.ndarray:
return np.array(arr)
def fake_candle(attributes=None, reset=False):
"""
:param attributes:
:param reset:
:return:
"""
def fake_candle(attributes: dict = None, reset: bool = False) -> np.ndarray:
global first_timestamp
global open_price
global close_price
@@ -71,7 +64,7 @@ def fake_candle(attributes=None, reset=False):
global low_price
if reset:
first_timestamp = 1552309186171
first_timestamp = 1609459080000
open_price = randint(40, 100)
close_price = randint(open_price, 110)
high_price = max(open_price, close_price)

View File

@@ -7,7 +7,7 @@ from jesse.models import Order
first_timestamp = 1552309186171
def fake_order(attributes=None):
def fake_order(attributes: dict = None) -> Order:
"""
:param attributes:

View File

@@ -5,7 +5,8 @@ import random
import string
import sys
import uuid
from typing import List, Tuple, Union, Any
from pprint import pprint
import arrow
import click
import numpy as np
@@ -13,21 +14,21 @@ import numpy as np
CACHED_CONFIG = dict()
def app_currency():
def app_currency() -> str:
from jesse.routes import router
return quote_asset(router.routes[0].symbol)
def app_mode():
def app_mode() -> str:
from jesse.config import config
return config['app']['trading_mode']
def arrow_to_timestamp(arrow_time):
def arrow_to_timestamp(arrow_time: arrow.arrow.Arrow) -> int:
return arrow_time.int_timestamp * 1000
def base_asset(symbol: str):
def base_asset(symbol: str) -> str:
return symbol.split('-')[0]
@@ -49,11 +50,16 @@ def binary_search(arr: list, item) -> int:
return -1
def clean_orderbook_list(arr):
def class_iter(Class):
return (value for variable, value in vars(Class).items() if
not callable(getattr(Class, variable)) and not variable.startswith("__"))
def clean_orderbook_list(arr) -> List[List[float]]:
return [[float(i[0]), float(i[1])] for i in arr]
def color(msg_text: str, msg_color: str):
def color(msg_text: str, msg_color: str) -> str:
if not msg_text:
return ''
@@ -71,36 +77,52 @@ def color(msg_text: str, msg_color: str):
return click.style(msg_text, fg='magenta')
if msg_color == 'cyan':
return click.style(msg_text, fg='cyan')
if msg_color in ['white', 'gray']:
if msg_color in {'white', 'gray'}:
return click.style(msg_text, fg='white')
raise ValueError('unsupported color')
def convert_number(old_max, old_min, new_max, new_min, old_value):
def convert_number(old_max: float, old_min: float, new_max: float, new_min: float, old_value: float) -> float:
"""
convert a number from one range (ex 40-119) to another
range (ex 0-30) while keeping the ratio.
"""
# validation
if old_value > old_max or old_value < old_min:
raise ValueError('old_value:{} must be within the range. {}-{}'.format(old_value, old_min, old_max))
raise ValueError(f'old_value:{old_value} must be within the range. {old_min}-{old_max}')
old_range = (old_max - old_min)
new_range = (new_max - new_min)
new_value = (((old_value - old_min) * new_range) / old_range) + new_min
return (((old_value - old_min) * new_range) / old_range) + new_min
return new_value
def dashless_symbol(symbol):
def dashless_symbol(symbol: str) -> str:
return symbol.replace("-", "")
def date_diff_in_days(date1, date2):
def dashy_symbol(symbol: str) -> str:
# if already has '-' in symbol, return symbol
if '-' in symbol:
return symbol
from jesse.config import config
for s in config['app']['considering_symbols']:
compare_symbol = dashless_symbol(s)
if compare_symbol == symbol:
return s
return f"{symbol[0:3]}-{symbol[3:]}"
def date_diff_in_days(date1: arrow.arrow.Arrow, date2: arrow.arrow.Arrow) -> int:
if type(date1) is not arrow.arrow.Arrow or type(
date2) is not arrow.arrow.Arrow:
raise TypeError('dates must be Arrow instances')
dif = date2 - date1
return abs(dif.days)
@@ -130,11 +152,10 @@ def dna_to_hp(strategy_hp, dna: str):
raise TypeError('Only int and float types are implemented')
hp[h['name']] = decoded_gene
return hp
def dump_exception():
def dump_exception() -> None:
"""
a useful debugging helper
"""
@@ -143,7 +164,8 @@ def dump_exception():
terminate_app()
def estimate_average_price(order_qty, order_price, current_qty, current_entry_price):
def estimate_average_price(order_qty: float, order_price: float, current_qty: float,
current_entry_price: float) -> float:
"""Estimates the new entry price for the position.
This is used after having a new order and updating the currently holding position.
@@ -160,7 +182,7 @@ def estimate_average_price(order_qty, order_price, current_qty, current_entry_pr
current_entry_price) / (abs(order_qty) + abs(current_qty))
def estimate_PNL(qty, entry_price, exit_price, trade_type, trading_fee=0):
def estimate_PNL(qty: float, entry_price: float, exit_price: float, trade_type: str, trading_fee: float = 0) -> float:
qty = abs(qty)
profit = qty * (exit_price - entry_price)
@@ -172,7 +194,7 @@ def estimate_PNL(qty, entry_price, exit_price, trade_type, trading_fee=0):
return profit - fee
def estimate_PNL_percentage(qty, entry_price, exit_price, trade_type):
def estimate_PNL_percentage(qty: float, entry_price: float, exit_price: float, trade_type: str) -> float:
qty = abs(qty)
profit = qty * (exit_price - entry_price)
@@ -186,20 +208,34 @@ def file_exists(path: str) -> bool:
return os.path.isfile(path)
def floor_with_precision(num, precision=0):
def clear_file(path: str) -> None:
with open(path, 'w') as f:
f.write('')
def make_directory(path: str) -> None:
if not os.path.exists(path):
os.makedirs(path)
def floor_with_precision(num: float, precision: int = 0) -> float:
temp = 10 ** precision
return math.floor(num * temp) / temp
def format_currency(num):
def format_currency(num: float) -> str:
return f'{num:,}'
def generate_unique_id():
def generate_unique_id() -> str:
return str(uuid.uuid4())
def get_candle_source(candles: np.ndarray, source_type="close") -> np.ndarray:
def get_arrow(timestamp: int) -> arrow.arrow.Arrow:
return timestamp_to_arrow(timestamp)
def get_candle_source(candles: np.ndarray, source_type: str = "close") -> np.ndarray:
"""
Returns the candles corresponding the selected type.
@@ -228,7 +264,7 @@ def get_candle_source(candles: np.ndarray, source_type="close") -> np.ndarray:
raise ValueError('type string not recognised')
def get_config(keys: str, default=None):
def get_config(keys: str, default: Any = None) -> Any:
"""
Gets keys as a single string separated with "." and returns value.
Also accepts a default value so that the app would work even if
@@ -242,29 +278,39 @@ def get_config(keys: str, default=None):
if not str:
raise ValueError('keys string cannot be empty')
if not keys in CACHED_CONFIG:
from functools import reduce
from jesse.config import config
CACHED_CONFIG[keys] = reduce(lambda d, k: d.get(k, default) if isinstance(d, dict) else default,
keys.split("."), config)
if is_unit_testing() or keys not in CACHED_CONFIG:
if os.environ.get(keys.upper().replace(".", "_").replace(" ", "_")) is not None:
CACHED_CONFIG[keys] = os.environ.get(keys.upper().replace(".", "_").replace(" ", "_"))
else:
from functools import reduce
from jesse.config import config
CACHED_CONFIG[keys] = reduce(lambda d, k: d.get(k, default) if isinstance(d, dict) else default,
keys.split("."), config)
return CACHED_CONFIG[keys]
def get_strategy_class(strategy_name):
def get_strategy_class(strategy_name: str):
from pydoc import locate
if is_unit_testing():
return locate('jesse.strategies.{}.{}'.format(strategy_name, strategy_name))
if not is_unit_testing():
return locate(f'strategies.{strategy_name}.{strategy_name}')
path = sys.path[0]
# live plugin
if path.endswith('jesse-live'):
strategy_dir = f'tests.strategies.{strategy_name}.{strategy_name}'
# main framework
else:
return locate('strategies.{}.{}'.format(strategy_name, strategy_name))
strategy_dir = f'jesse.strategies.{strategy_name}.{strategy_name}'
return locate(strategy_dir)
def insecure_hash(msg: str) -> str:
return hashlib.md5(msg.encode()).hexdigest()
def insert_list(index: int, item, arr: list):
def insert_list(index: int, item, arr: list) -> list:
"""
helper to insert an item in a Python List without removing the item
"""
@@ -274,71 +320,83 @@ def insert_list(index: int, item, arr: list):
return arr[:index] + [item] + arr[index:]
def is_backtesting():
def is_backtesting() -> bool:
from jesse.config import config
return config['app']['trading_mode'] == 'backtest'
def is_collecting_data():
def is_collecting_data() -> bool:
from jesse.config import config
return config['app']['trading_mode'] == 'collect'
def is_debuggable(debug_item):
def is_debuggable(debug_item) -> bool:
from jesse.config import config
return is_debugging() and config['env']['logging'][debug_item]
def is_debugging():
def is_debugging() -> bool:
from jesse.config import config
return config['app']['debug_mode']
def is_importing_candles():
def is_importing_candles() -> bool:
from jesse.config import config
return config['app']['trading_mode'] == 'import-candles'
return config['app']['trading_mode'] == 'candles'
def is_live():
def is_live() -> bool:
return is_livetrading() or is_paper_trading()
def is_livetrading():
def is_livetrading() -> bool:
from jesse.config import config
return config['app']['trading_mode'] == 'livetrade'
def is_optimizing():
def is_optimizing() -> bool:
from jesse.config import config
return config['app']['trading_mode'] == 'optimize'
def is_paper_trading():
def is_paper_trading() -> bool:
from jesse.config import config
return config['app']['trading_mode'] == 'papertrade'
def is_test_driving():
def is_test_driving() -> bool:
from jesse.config import config
return config['app']['is_test_driving']
def is_unit_testing():
return "pytest" in sys.modules
def is_unit_testing() -> bool:
from jesse.config import config
# config['app']['is_unit_testing'] is only set in the live plugin unit tests
return "pytest" in sys.modules or config['app']['is_unit_testing']
def key(exchange, symbol, timeframe=None):
def is_valid_uuid(uuid_to_test:str, version: int = 4) -> bool:
try:
uuid_obj = uuid.UUID(uuid_to_test, version=version)
except ValueError:
return False
return str(uuid_obj) == uuid_to_test
def key(exchange: str, symbol: str, timeframe: str = None):
if timeframe is None:
return '{}-{}'.format(exchange, symbol)
return f'{exchange}-{symbol}'
return '{}-{}-{}'.format(exchange, symbol, timeframe)
return f'{exchange}-{symbol}-{timeframe}'
def max_timeframe(timeframes_list):
def max_timeframe(timeframes_list: list) -> str:
from jesse.enums import timeframes
if timeframes.DAY_1 in timeframes_list:
return timeframes.DAY_1
if timeframes.HOUR_12 in timeframes_list:
return timeframes.HOUR_12
if timeframes.HOUR_8 in timeframes_list:
return timeframes.HOUR_8
if timeframes.HOUR_6 in timeframes_list:
@@ -351,6 +409,8 @@ def max_timeframe(timeframes_list):
return timeframes.HOUR_2
if timeframes.HOUR_1 in timeframes_list:
return timeframes.HOUR_1
if timeframes.MINUTE_45 in timeframes_list:
return timeframes.MINUTE_45
if timeframes.MINUTE_30 in timeframes_list:
return timeframes.MINUTE_30
if timeframes.MINUTE_15 in timeframes_list:
@@ -363,27 +423,51 @@ def max_timeframe(timeframes_list):
return timeframes.MINUTE_1
def normalize(x, x_min, x_max):
def normalize(x: float, x_min: float, x_max: float) -> float:
"""
Rescaling data to have values between 0 and 1
"""
x_new = (x - x_min) / (x_max - x_min)
return x_new
return (x - x_min) / (x_max - x_min)
def now_to_timestamp():
if not (is_live() or is_collecting_data() or is_importing_candles()):
def now(force_fresh=False) -> int:
"""
Always returns the current time in milliseconds but rounds time in matter of seconds
"""
return now_to_timestamp(force_fresh)
def now_to_timestamp(force_fresh=False) -> int:
if not force_fresh and (not (is_live() or is_collecting_data() or is_importing_candles())):
from jesse.store import store
return store.app.time
return arrow.utcnow().int_timestamp * 1000
def now():
return now_to_timestamp()
def current_1m_candle_timestamp():
return arrow.utcnow().floor('minute').int_timestamp * 1000
def np_shift(arr: np.ndarray, num: int, fill_value=0):
def np_ffill(arr: np.ndarray, axis: int = 0) -> np.ndarray:
idx_shape = tuple([slice(None)] + [np.newaxis] * (len(arr.shape) - axis - 1))
idx = np.where(~np.isnan(arr), np.arange(arr.shape[axis])[idx_shape], 0)
np.maximum.accumulate(idx, axis=axis, out=idx)
slc = [
np.arange(k)[
tuple(
slice(None) if dim == i else np.newaxis
for dim in range(len(arr.shape))
)
]
for i, k in enumerate(arr.shape)
]
slc[axis] = idx
return arr[tuple(slc)]
def np_shift(arr: np.ndarray, num: int, fill_value=0) -> np.ndarray:
result = np.empty_like(arr)
if num > 0:
@@ -398,17 +482,18 @@ def np_shift(arr: np.ndarray, num: int, fill_value=0):
return result
def opposite_side(s):
def opposite_side(s: str) -> str:
from jesse.enums import sides
if s == sides.BUY:
return sides.SELL
if s == sides.SELL:
elif s == sides.SELL:
return sides.BUY
raise ValueError('unsupported side')
else:
raise ValueError(f'{s} is not a valid input for side')
def opposite_type(t):
def opposite_type(t: str) -> str:
from jesse.enums import trade_types
if t == trade_types.LONG:
@@ -418,15 +503,15 @@ def opposite_type(t):
raise ValueError('unsupported type')
def orderbook_insertion_index_search(arr, target, ascending=True):
def orderbook_insertion_index_search(arr, target: int, ascending: bool = True) -> Tuple[bool, int]:
target = target[0]
lower = 0
upper = len(arr)
if ascending:
while lower < upper:
x = lower + (upper - lower) // 2
val = arr[x][0]
while lower < upper:
x = lower + (upper - lower) // 2
val = arr[x][0]
if ascending:
if target == val:
return True, x
elif target > val:
@@ -437,30 +522,19 @@ def orderbook_insertion_index_search(arr, target, ascending=True):
if lower == x:
return False, lower
upper = x
else:
while lower < upper:
x = lower + (upper - lower) // 2
val = arr[x][0]
if target == val:
return True, x
elif target < val:
if lower == x:
return False, lower + 1
lower = x
elif target > val:
if lower == x:
return False, lower
upper = x
elif target == val:
return True, x
elif target < val:
if lower == x:
return False, lower + 1
lower = x
elif target > val:
if lower == x:
return False, lower
upper = x
def orderbook_trim_price(p: float, ascending: bool, unit: float):
"""
:param p:
:param ascending:
:param unit:
:return:
"""
def orderbook_trim_price(p: float, ascending: bool, unit: float) -> float:
if ascending:
trimmed = np.ceil(p / unit) * unit
if math.log10(unit) < 0:
@@ -473,33 +547,32 @@ def orderbook_trim_price(p: float, ascending: bool, unit: float):
return p if trimmed == p - unit else trimmed
def prepare_qty(qty, side):
def prepare_qty(qty: float, side: str) -> float:
if side.lower() in ('sell', 'short'):
return -abs(qty)
if side.lower() in ('buy', 'long'):
elif side.lower() in ('buy', 'long'):
return abs(qty)
raise TypeError()
else:
raise ValueError(f'{side} is not a valid input')
def python_version() -> float:
return float('{}.{}'.format(sys.version_info[0], sys.version_info[1]))
def python_version() -> tuple:
return sys.version_info[:2]
def quote_asset(symbol: str):
def quote_asset(symbol: str) -> str:
try:
return symbol.split('-')[1]
except IndexError:
from jesse.exceptions import InvalidRoutes
raise InvalidRoutes("The symbol format is incorrect. Correct example: 'BTC-USDT'. Yours is '{}'".format(symbol))
raise InvalidRoutes(f"The symbol format is incorrect. Correct example: 'BTC-USDT'. Yours is '{symbol}'")
def random_str(num_characters=8):
return ''.join(random.choice(string.ascii_letters) for i in range(num_characters))
def random_str(num_characters: int = 8) -> str:
return ''.join(random.choice(string.ascii_letters) for _ in range(num_characters))
def readable_duration(seconds, granularity=2):
def readable_duration(seconds: int, granularity: int = 2) -> str:
intervals = (
('weeks', 604800), # 60 * 60 * 24 * 7
('days', 86400), # 60 * 60 * 24
@@ -509,6 +582,7 @@ def readable_duration(seconds, granularity=2):
)
result = []
seconds = int(seconds)
for name, count in intervals:
value = seconds // count
@@ -516,7 +590,7 @@ def readable_duration(seconds, granularity=2):
seconds -= value * count
if value == 1:
name = name.rstrip('s')
result.append("{} {}".format(value, name))
result.append(f"{value} {name}")
return ', '.join(result[:granularity])
@@ -524,44 +598,52 @@ def relative_to_absolute(path: str) -> str:
return os.path.abspath(path)
def round_price_for_live_mode(price, roundable_price):
def round_price_for_live_mode(price, precision: int) -> Union[float, np.ndarray]:
"""
Rounds price(s) based on exchange requirements
:param price: float
:param roundable_price: float | nd.array
:param precision: int
:return: float | nd.array
"""
n = int(math.log10(price))
if price < 1:
price_round_precision = abs(n - 4)
else:
price_round_precision = 3 - n
if price_round_precision < 0:
price_round_precision = 0
return np.round(roundable_price, price_round_precision)
return np.round(price, precision)
def round_qty_for_live_mode(price, roundable_qty):
def round_qty_for_live_mode(roundable_qty: float, precision: int) -> Union[float, np.ndarray]:
"""
Rounds qty(s) based on exchange requirements
:param price: float
:param roundable_qty: float | nd.array
:param precision: int
:return: float | nd.array
"""
n = int(math.log10(price))
# for qty rounding down is important to prevent InsufficenMargin
rounded = round_decimals_down(roundable_qty, precision)
if price < 1:
qty_round_precision = 0
else:
qty_round_precision = n + 1
if qty_round_precision > 3:
qty_round_precision = 3
for index, q in enumerate(rounded):
if q == 0.0:
rounded[index] = 1 / 10 ** precision
return np.round(roundable_qty, qty_round_precision)
return rounded
def round_decimals_down(number: np.ndarray, decimals: int = 2) -> float:
"""
Returns a value rounded down to a specific number of decimal places.
"""
if not isinstance(decimals, int):
raise TypeError("decimal places must be an integer")
elif decimals < 0:
raise ValueError("decimal places has to be 0 or more")
elif decimals == 0:
return np.floor(number)
factor = 10 ** decimals
return np.floor(number * factor) / factor
def same_length(bigger: np.ndarray, shorter: np.ndarray) -> np.ndarray:
return np.concatenate((np.full((bigger.shape[0] - shorter.shape[0]), np.nan), shorter))
def secure_hash(msg: str) -> str:
@@ -572,9 +654,12 @@ def should_execute_silently() -> bool:
return is_optimizing() or is_unit_testing()
def side_to_type(s):
def side_to_type(s: str) -> str:
from jesse.enums import trade_types, sides
# make sure string is lowercase
s = s.lower()
if s == sides.BUY:
return trade_types.LONG
if s == sides.SELL:
@@ -582,14 +667,21 @@ def side_to_type(s):
raise ValueError
def string_after_character(string: str, character: str):
def string_after_character(s: str, character: str) -> str:
try:
return string.split(character, 1)[1]
return s.split(character, 1)[1]
except IndexError:
return None
def style(msg_text: str, msg_style: str):
def slice_candles(candles: np.ndarray, sequential: bool) -> np.ndarray:
warmup_candles_num = get_config('env.data.warmup_candles_num', 240)
if not sequential and candles.shape[0] > warmup_candles_num:
candles = candles[-warmup_candles_num:]
return candles
def style(msg_text: str, msg_style: str) -> str:
if msg_style is None:
return msg_text
@@ -602,15 +694,32 @@ def style(msg_text: str, msg_style: str):
raise ValueError('unsupported style')
def terminate_app():
def terminate_app() -> None:
# close the database
from jesse.services.db import close_connection
close_connection()
from jesse.services.db import database
database.close_connection()
# disconnect python from the OS
os._exit(1)
def timeframe_to_one_minutes(timeframe):
def error(msg: str, force_print: bool = False) -> None:
# send notifications if it's a live session
if is_live():
from jesse.services import logger
logger.error(msg)
if force_print:
_print_error(msg)
else:
_print_error(msg)
def _print_error(msg: str) -> None:
print('\n')
print(color('========== critical error =========='.upper(), 'red'))
print(color(msg, 'red'))
def timeframe_to_one_minutes(timeframe: str) -> int:
from jesse.enums import timeframes
from jesse.exceptions import InvalidTimeframe
@@ -620,36 +729,34 @@ def timeframe_to_one_minutes(timeframe):
timeframes.MINUTE_5: 5,
timeframes.MINUTE_15: 15,
timeframes.MINUTE_30: 30,
timeframes.MINUTE_45: 45,
timeframes.HOUR_1: 60,
timeframes.HOUR_2: 60 * 2,
timeframes.HOUR_3: 60 * 3,
timeframes.HOUR_4: 60 * 4,
timeframes.HOUR_6: 60 * 6,
timeframes.HOUR_8: 60 * 8,
timeframes.HOUR_12: 60 * 12,
timeframes.DAY_1: 60 * 24,
}
try:
return dic[timeframe]
except KeyError:
all_timeframes = [timeframe for timeframe in class_iter(timeframes)]
raise InvalidTimeframe(
'Timeframe "{}" is invalid. Supported timeframes are 1m, 3m, 5m, 15m, 30m, 1h, 2h, 3h, 4h, 6h, 8h, 1D'.format(
timeframe))
f'Timeframe "{timeframe}" is invalid. Supported timeframes are {", ".join(all_timeframes)}.')
def timestamp_to_arrow(timestamp):
def timestamp_to_arrow(timestamp: int) -> arrow.arrow.Arrow:
return arrow.get(timestamp / 1000)
def get_arrow(timestamp):
return timestamp_to_arrow(timestamp)
def timestamp_to_date(timestamp: int) -> str:
return str(arrow.get(timestamp / 1000))[:10]
def timestamp_to_time(timestamp):
def timestamp_to_time(timestamp: int) -> str:
return str(arrow.get(timestamp / 1000))
@@ -662,7 +769,7 @@ def today_to_timestamp() -> int:
return arrow.utcnow().floor('day').int_timestamp * 1000
def type_to_side(t):
def type_to_side(t: str) -> str:
from jesse.enums import trade_types, sides
if t == trade_types.LONG:
@@ -681,3 +788,165 @@ def unique_list(arr) -> list:
seen = set()
seen_add = seen.add
return [x for x in arr if not (x in seen or seen_add(x))]
def closing_side(position_type: str) -> str:
if position_type.lower() == 'long':
return 'sell'
elif position_type.lower() == 'short':
return 'buy'
else:
raise ValueError(f'Value entered for position_type ({position_type}) is not valid')
def merge_dicts(d1: dict, d2: dict) -> dict:
"""
Merges nested dictionaries
:param d1: dict
:param d2: dict
:return: dict
"""
def inner(dict1, dict2):
for k in set(dict1.keys()).union(dict2.keys()):
if k in dict1 and k in dict2:
if isinstance(dict1[k], dict) and isinstance(dict2[k], dict):
yield k, dict(merge_dicts(dict1[k], dict2[k]))
else:
yield k, dict2[k]
elif k in dict1:
yield k, dict1[k]
else:
yield k, dict2[k]
return dict(inner(d1, d2))
def computer_name():
import platform
return platform.node()
def validate_response(response):
if response.status_code != 200:
err_msg = f"[{response.status_code}]: {response.json()['message']}\nPlease contact us at support@jesse.trade if this is unexpected."
if response.status_code not in [401, 403]:
raise ConnectionError(err_msg)
error(err_msg, force_print=True)
terminate_app()
def get_session_id():
from jesse.store import store
return store.app.session_id
def get_pid():
return os.getpid()
def is_jesse_project():
ls = os.listdir('.')
return 'strategies' in ls and 'storage' in ls
def dd(item, pretty=True):
"""
Dump and Die but pretty: used for debugging when developing Jesse
"""
dump(item, pretty)
terminate_app()
def dump(item, pretty=True):
"""
Dump object in pretty format: used for debugging when developing Jesse
"""
print(
color('\n========= Debugging Value =========='.upper(), 'yellow')
)
if pretty:
pprint(item)
else:
print(item)
print(
color('====================================\n', 'yellow')
)
def float_or_none(item):
"""
Return the float of the value if it's not None
"""
if item is None:
return None
else:
return float(item)
def str_or_none(item, encoding='utf-8'):
"""
Return the str of the value if it's not None
"""
if item is None:
return None
else:
# return item if it's str, if not, decode it using encoding
if isinstance(item, str):
return item
return str(item, encoding)
def get_settlement_currency_from_exchange(exchange: str):
if exchange in {'FTX Futures', 'Bitfinex', 'Coinbase'}:
return 'USD'
else:
return 'USDT'
def cpu_cores_count():
from multiprocessing import cpu_count
return cpu_count()
# a function that converts name to env_name. Example: 'Testnet Binance Futures' into 'TESTNET_BINANCE_FUTURES'
def convert_to_env_name(name: str) -> str:
return name.replace(' ', '_').upper()
def is_notebook():
try:
shell = get_ipython().__class__.__name__
# Jupyter notebook or qtconsole
if shell == 'ZMQInteractiveShell':
return True
elif shell == 'TerminalInteractiveShell':
# Terminal running IPython
return False
else:
# Other type (?)
return False
except NameError:
# Probably standard Python interpreter
return False
def get_os() -> str:
import platform
if platform.system() == 'Darwin':
return 'mac'
elif platform.system() == 'Linux':
return 'linux'
elif platform.system() == 'Windows':
return 'windows'
else:
raise NotImplementedError(f'Unsupported OS: "{platform.system()}"')
# a function that returns boolean whether or not the code is being executed inside a docker container
def is_docker() -> bool:
import os
return os.path.exists('/.dockerenv')

View File

@@ -4,68 +4,95 @@ from .adosc import adosc
from .adx import adx
from .adxr import adxr
from .alligator import alligator
from .alma import alma
from .ao import ao
from .apo import apo
from .aroon import aroon
from .aroonosc import aroonosc
from .atr import atr
from .avgprice import avgprice
from .bandpass import bandpass
from .beta import beta
from .bollinger_bands import bollinger_bands
from .bollinger_bands_width import bollinger_bands_width
from .bop import bop
from .cc import cc
from .cci import cci
from .cfo import cfo
from .cg import cg
from .chande import chande
from .chop import chop
from .cksp import cksp
from .cmo import cmo
from .correlation_cycle import correlation_cycle
from .correl import correl
from .correlation_cycle import correlation_cycle
from .cvi import cvi
from .cwma import cwma
from .damiani_volatmeter import damiani_volatmeter
from .dec_osc import dec_osc
from .decycler import decycler
from .dema import dema
from .devstop import devstop
from .di import di
from .dm import dm
from .dx import dx
from .donchian import donchian
from .dpo import dpo
from .dti import dti
from .dx import dx
from .edcf import edcf
from .efi import efi
from .ema import ema
from .emd import emd
from .emv import emv
from .epma import epma
from .er import er
from .eri import eri
from .fisher import fisher
from .fosc import fosc
from .frama import frama
from .fwma import fwma
from .gatorosc import gatorosc
from .gauss import gauss
from .hma import hma
from .high_pass import high_pass
from .high_pass_2_pole import high_pass_2_pole
from .hma import hma
from .ht_dcperiod import ht_dcperiod
from .ht_dcphase import ht_dcphase
from .ht_phasor import ht_phasor
from .ht_sine import ht_sine
from .ht_trendline import ht_trendline
from .ht_trendmode import ht_trendmode
from .hurst_exponent import hurst_exponent
from .hwma import hwma
from .ichimoku_cloud import ichimoku_cloud
from .ichimoku_cloud_seq import ichimoku_cloud_seq
from .ift_rsi import ift_rsi
from .itrend import itrend
from .jma import jma
from .jsa import jsa
from .kama import kama
from .kaufmanstop import kaufmanstop
from .kdj import kdj
from .keltner import keltner
from .kst import kst
from .kurtosis import kurtosis
from .kvo import kvo
from .linearreg import linearreg
from .linearreg_angle import linearreg_angle
from .linearreg_intercept import linearreg_intercept
from .linearreg_slope import linearreg_slope
from .lrsi import lrsi
from .ma import ma
from .maaq import maaq
from .mab import mab
from .macd import macd
from .macdext import macdext
from .mama import mama
from .marketfi import marketfi
from .mass import mass
from .mcginley_dynamic import mcginley_dynamic
from .marketfi import marketfi
from .mean_ad import mean_ad
from .median_ad import median_ad
from .medprice import medprice
from .mfi import mfi
from .midpoint import midpoint
@@ -73,31 +100,48 @@ from .midprice import midprice
from .minmax import minmax
from .mom import mom
from .msw import msw
from .mwdx import mwdx
from .natr import natr
from .nma import nma
from .nvi import nvi
from .obv import obv
from .pattern_recognition import pattern_recognition
from .pfe import pfe
from .pivot import pivot
from .pma import pma
from .ppo import ppo
from .pvi import pvi
from .pwma import pwma
from .qstick import qstick
from .reflex import reflex
from .rma import rma
from .roc import roc
from .roofing import roofing
from .rocp import rocp
from .rocr import rocr
from .rocr100 import rocr100
from .roofing import roofing
from .rsi import rsi
from .rsmk import rsmk
from .rsx import rsx
from .rvi import rvi
from .safezonestop import safezonestop
from .sar import sar
from .sarext import sarext
from .sinwma import sinwma
from .skew import skew
from .sma import sma
from .smma import smma
from .sqwma import sqwma
from .srsi import srsi
from .srwma import srwma
from .stc import stc
from .stddev import stddev
from .stochastic import stoch
from .stochf import stochf
from .supersmoother import supersmoother
from .supersmoother_3_pole import supersmoother_3_pole
from .supertrend import supertrend
from .swma import swma
from .t3 import t3
from .tema import tema
from .trange import trange
@@ -106,21 +150,27 @@ from .trima import trima
from .trix import trix
from .tsf import tsf
from .tsi import tsi
from .ttm_trend import ttm_trend
from .typprice import typprice
from .ui import ui
from .ultosc import ultosc
from .var import var
from .vi import vi
from .vidya import vidya
from .vpci import vpci
from .vpt import vpt
from .vwma import vwma
from .vwmacd import vwmacd
from .vlma import vlma
from .vosc import vosc
from .voss import voss
from .vpci import vpci
from .vpt import vpt
from .vpwma import vpwma
from .vwap import vwap
from .vwma import vwma
from .vwmacd import vwmacd
from .wad import wad
from .wclprice import wclprice
from .wilders import wilders
from .willr import willr
from .wma import wma
from .wt import wt
from .zlema import zlema
from .zscore import zscore

View File

@@ -3,20 +3,21 @@ from collections import namedtuple
import numpy as np
import talib
from jesse.helpers import slice_candles
AC = namedtuple('AC', ['osc', 'change'])
def acosc(candles: np.ndarray, sequential=False) -> AC:
def acosc(candles: np.ndarray, sequential: bool = False) -> AC:
"""
Acceleration / Deceleration Oscillator (AC)
:param candles: np.ndarray
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: AC(osc, change)
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
med = talib.MEDPRICE(candles[:, 3], candles[:, 4])
ao = talib.SMA(med, 5) - talib.SMA(med, 34)

View File

@@ -3,22 +3,20 @@ from typing import Union
import numpy as np
import talib
from jesse.helpers import slice_candles
def ad(candles: np.ndarray, sequential=False) -> Union[float, np.ndarray]:
def ad(candles: np.ndarray, sequential: bool = False) -> Union[float, np.ndarray]:
"""
AD - Chaikin A/D Line
:param candles: np.ndarray
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
res = talib.AD(candles[:, 3], candles[:, 4], candles[:, 2], candles[:, 5])
if sequential:
return res
else:
return None if np.isnan(res[-1]) else res[-1]
return res if sequential else res[-1]

View File

@@ -3,25 +3,24 @@ from typing import Union
import numpy as np
import talib
from jesse.helpers import slice_candles
def adosc(candles: np.ndarray, fastperiod=3, slowperiod=10, sequential=False) -> Union[float, np.ndarray]:
def adosc(candles: np.ndarray, fast_period: int = 3, slow_period: int = 10, sequential: bool = False) -> Union[
float, np.ndarray]:
"""
ADOSC - Chaikin A/D Oscillator
:param candles: np.ndarray
:param fastperiod: int - default: 3
:param slowperiod: int - default: 10
:param sequential: bool - default=False
:param fast_period: int - default: 3
:param slow_period: int - default: 10
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
res = talib.ADOSC(candles[:, 3], candles[:, 4], candles[:, 2], candles[:, 5], fastperiod=fastperiod,
slowperiod=slowperiod)
res = talib.ADOSC(candles[:, 3], candles[:, 4], candles[:, 2], candles[:, 5], fastperiod=fast_period,
slowperiod=slow_period)
if sequential:
return res
else:
return None if np.isnan(res[-1]) else res[-1]
return res if sequential else res[-1]

View File

@@ -3,23 +3,21 @@ from typing import Union
import numpy as np
import talib
from jesse.helpers import slice_candles
def adx(candles: np.ndarray, period=14, sequential=False) -> Union[float, np.ndarray]:
def adx(candles: np.ndarray, period: int = 14, sequential: bool = False) -> Union[float, np.ndarray]:
"""
ADX - Average Directional Movement Index
:param candles: np.ndarray
:param period: int - default=14
:param sequential: bool - default=False
:param period: int - default: 14
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
res = talib.ADX(candles[:, 3], candles[:, 4], candles[:, 2], timeperiod=period)
if sequential:
return res
else:
return None if np.isnan(res[-1]) else res[-1]
return res if sequential else res[-1]

View File

@@ -3,23 +3,21 @@ from typing import Union
import numpy as np
import talib
from jesse.helpers import slice_candles
def adxr(candles: np.ndarray, period=14, sequential=False) -> Union[float, np.ndarray]:
def adxr(candles: np.ndarray, period: int = 14, sequential: bool = False) -> Union[float, np.ndarray]:
"""
ADXR - Average Directional Movement Index Rating
:param candles: np.ndarray
:param period: int - default=14
:param sequential: bool - default=False
:param period: int - default: 14
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
res = talib.ADXR(candles[:, 3], candles[:, 4], candles[:, 2], timeperiod=period)
if sequential:
return res
else:
return None if np.isnan(res[-1]) else res[-1]
return res if sequential else res[-1]

View File

@@ -2,23 +2,22 @@ from collections import namedtuple
import numpy as np
from jesse.helpers import get_candle_source, np_shift
from jesse.helpers import get_candle_source, np_shift, slice_candles
AG = namedtuple('AG', ['jaw', 'teeth', 'lips'])
def alligator(candles: np.ndarray, source_type="close", sequential=False) -> AG:
def alligator(candles: np.ndarray, source_type: str = "close", sequential: bool = False) -> AG:
"""
Alligator
:param candles: np.ndarray
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: AG(jaw, teeth, lips)
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
@@ -32,7 +31,7 @@ def alligator(candles: np.ndarray, source_type="close", sequential=False) -> AG:
return AG(jaw[-1], teeth[-1], lips[-1])
def numpy_ewma(data, window):
def numpy_ewma(data: np.ndarray, window: int):
"""
:param data:
@@ -40,13 +39,11 @@ def numpy_ewma(data, window):
:return:
"""
alpha = 1 / window
scale = 1 / (1 - alpha)
# scale = 1 / (1 - alpha)
n = data.shape[0]
scale_arr = (1 - alpha) ** (-1 * np.arange(n))
weights = (1 - alpha) ** np.arange(n)
pw0 = (1 - alpha) ** (n - 1)
mult = data * pw0 * scale_arr
cumsums = mult.cumsum()
out = cumsums * scale_arr[::-1] / weights.cumsum()
return out
return cumsums * scale_arr[::-1] / weights.cumsum()

54
jesse/indicators/alma.py Normal file
View File

@@ -0,0 +1,54 @@
from typing import Union
import numpy as np
from jesse.helpers import get_candle_source, slice_candles
def alma(candles: np.ndarray, period: int = 9, sigma: float = 6.0, distribution_offset: float = 0.85,
source_type: str = "close", sequential: bool = False) -> Union[
float, np.ndarray]:
"""
ALMA - Arnaud Legoux Moving Average
:param candles: np.ndarray
:param period: int - default: 9
:param sigma: float - default: 6.0
:param distribution_offset: float - default: 0.85
:param source_type: str - default: "close"
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if len(candles.shape) == 1:
source = candles
else:
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
asize = period - 1
m = distribution_offset * asize
s = period / sigma
dss = 2 * s * s
wtds = np.exp(-(np.arange(period) - m) ** 2 / dss)
pnp_array3D = strided_axis0(source, len(wtds))
res = np.zeros(source.shape)
res[period - 1:] = np.tensordot(pnp_array3D, wtds, axes=(1, 0))[:]
res /= wtds.sum()
res[res == 0] = np.nan
return res if sequential else res[-1]
def strided_axis0(a, L):
# Store the shape and strides info
shp = a.shape
s = a.strides
# Compute length of output array along the first axis
nd0 = shp[0] - L + 1
# Setup shape and strides for use with np.lib.stride_tricks.as_strided
# and get (n+1) dim output array
shp_in = (nd0, L) + shp[1:]
strd_in = (s[0],) + s
return np.lib.stride_tricks.as_strided(a, shape=shp_in, strides=strd_in)

View File

@@ -3,20 +3,21 @@ from collections import namedtuple
import numpy as np
import talib
from jesse.helpers import slice_candles
AO = namedtuple('AO', ['osc', 'change'])
def ao(candles: np.ndarray, sequential=False) -> AO:
def ao(candles: np.ndarray, sequential: bool = False) -> AO:
"""
Awesome Oscillator
:param candles: np.ndarray
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: AO(osc, change)
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
med = talib.MEDPRICE(candles[:, 3], candles[:, 4])
res = talib.SMA(med, 5) - talib.SMA(med, 34)

View File

@@ -1,30 +1,29 @@
from typing import Union
import numpy as np
import talib
from jesse.indicators.ma import ma
from jesse.helpers import get_candle_source
from jesse.helpers import get_candle_source, slice_candles
def apo(candles: np.ndarray, fastperiod=12, slowperiod=26, matype=0, source_type="close", sequential=False) -> Union[
float, np.ndarray]:
def apo(candles: np.ndarray, fast_period: int = 12, slow_period: int = 26, matype: int = 0, source_type: str = "close",
sequential: bool = False) -> Union[float, np.ndarray]:
"""
APO - Absolute Price Oscillator
:param candles: np.ndarray
:param fastperiod: int - default: 12
:param slowperiod: int - default: 26
:param fast_period: int - default: 12
:param slow_period: int - default: 26
:param matype: int - default: 0
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
res = talib.APO(source, fastperiod=fastperiod, slowperiod=slowperiod, matype=matype)
res = ma(source, period=fast_period, matype=matype, sequential=True) - ma(source, period=slow_period, matype=matype, sequential=True)
return res if sequential else res[-1]

View File

@@ -3,21 +3,22 @@ from collections import namedtuple
import numpy as np
import talib
from jesse.helpers import slice_candles
AROON = namedtuple('AROON', ['down', 'up'])
def aroon(candles: np.ndarray, period=14, sequential=False) -> AROON:
def aroon(candles: np.ndarray, period: int = 14, sequential: bool = False) -> AROON:
"""
AROON - Aroon
:param candles: np.ndarray
:param period: int - default=14
:param sequential: bool - default=False
:param period: int - default: 14
:param sequential: bool - default: False
:return: AROON(down, up)
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
aroondown, aroonup = talib.AROON(candles[:, 3], candles[:, 4], timeperiod=period)

View File

@@ -3,23 +3,21 @@ from typing import Union
import numpy as np
import talib
from jesse.helpers import slice_candles
def aroonosc(candles: np.ndarray, period=14, sequential=False) -> Union[float, np.ndarray]:
def aroonosc(candles: np.ndarray, period: int = 14, sequential: bool = False) -> Union[float, np.ndarray]:
"""
AROONOSC - Aroon Oscillator
:param candles: np.ndarray
:param period: int - default=14
:param sequential: bool - default=False
:param period: int - default: 14
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
res = talib.AROONOSC(candles[:, 3], candles[:, 4], timeperiod=period)
if sequential:
return res
else:
return None if np.isnan(res[-1]) else res[-1]
return res if sequential else res[-1]

View File

@@ -3,23 +3,21 @@ from typing import Union
import numpy as np
import talib
from jesse.helpers import slice_candles
def atr(candles: np.ndarray, period=14, sequential=False) -> Union[float, np.ndarray]:
def atr(candles: np.ndarray, period: int = 14, sequential: bool = False) -> Union[float, np.ndarray]:
"""
ATR - Average True Range
:param candles: np.ndarray
:param period: int - default=14
:param sequential: bool - default=False
:param period: int - default: 14
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
res = talib.ATR(candles[:, 3], candles[:, 4], candles[:, 2], timeperiod=period)
if sequential:
return res
else:
return None if np.isnan(res[-1]) else res[-1]
return res if sequential else res[-1]

View File

@@ -3,22 +3,20 @@ from typing import Union
import numpy as np
import talib
from jesse.helpers import slice_candles
def avgprice(candles: np.ndarray, sequential=False) -> Union[float, np.ndarray]:
def avgprice(candles: np.ndarray, sequential: bool = False) -> Union[float, np.ndarray]:
"""
AVGPRICE - Average Price
:param candles: np.ndarray
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
res = talib.AVGPRICE(candles[:, 1], candles[:, 3], candles[:, 4], candles[:, 2])
if sequential:
return res
else:
return None if np.isnan(res[-1]) else res[-1]
return res if sequential else res[-1]

View File

@@ -0,0 +1,68 @@
from collections import namedtuple
import numpy as np
try:
from numba import njit
except ImportError:
njit = lambda a : a
from .high_pass import high_pass_fast
from jesse.helpers import get_candle_source, slice_candles
BandPass = namedtuple('BandPass', ['bp', 'bp_normalized', 'signal', 'trigger'])
def bandpass(candles: np.ndarray, period: int = 20, bandwidth: float = 0.3, source_type: str = "close", sequential: bool = False) -> BandPass:
"""
BandPass Filter
:param candles: np.ndarray
:param period: int - default: 20
:param bandwidth: float - default: 0.3
:param source_type: str - default: "close"
:param sequential: bool - default: False
:return: BandPass(bp, bp_normalized, signal, trigger)
"""
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
hp = high_pass_fast(source, 4 * period / bandwidth)
beta = np.cos(2 * np.pi / period)
gamma = np.cos(2 * np.pi * bandwidth / period)
alpha = 1 / gamma - np.sqrt(1 / gamma ** 2 - 1)
bp, peak = bp_fast(source, hp, alpha, beta)
bp_normalized = bp / peak
trigger = high_pass_fast(bp_normalized, period / bandwidth / 1.5)
signal = (bp_normalized < trigger) * 1 - (trigger < bp_normalized) * 1
if sequential:
return BandPass(bp, bp_normalized, signal, trigger)
else:
return BandPass(bp[-1], bp_normalized[-1], signal[-1], trigger[-1])
@njit
def bp_fast(source, hp, alpha, beta): # Function is compiled to machine code when called the first time
bp = np.copy(hp)
for i in range(2, source.shape[0]):
bp[i] = 0.5 * (1 - alpha) * hp[i] - (1 - alpha) * 0.5 * hp[i - 2] + beta * (1 + alpha) * bp[i - 1] - alpha * bp[i - 2]
# fast attack-slow decay AGC
K = 0.991
peak = np.copy(bp)
for i in range(source.shape[0]):
if i > 0:
peak[i] = peak[i - 1] * K
if np.abs(bp[i]) > peak[i]:
peak[i] = np.abs(bp[i])
return bp, peak

View File

@@ -3,23 +3,21 @@ from typing import Union
import numpy as np
import talib
from jesse.helpers import slice_candles
def beta(candles: np.ndarray, period=5, sequential=False) -> Union[float, np.ndarray]:
def beta(candles: np.ndarray, period: int = 5, sequential: bool = False) -> Union[float, np.ndarray]:
"""
BETA - Beta
:param candles: np.ndarray
:param period: int - default: 5
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
res = talib.BETA(candles[:, 3], candles[:, 4], timeperiod=period)
if sequential:
return res
else:
return None if np.isnan(res[-1]) else res[-1]
return res if sequential else res[-1]

View File

@@ -2,14 +2,18 @@ from collections import namedtuple
import numpy as np
import talib
from jesse.indicators.ma import ma
from jesse.indicators.mean_ad import mean_ad
from jesse.indicators.median_ad import median_ad
from jesse.helpers import get_candle_source
from jesse.helpers import get_candle_source, slice_candles
BollingerBands = namedtuple('BollingerBands', ['upperband', 'middleband', 'lowerband'])
def bollinger_bands(candles: np.ndarray, period=20, devup=2, devdn=2, matype=0, source_type="close",
sequential=False) -> BollingerBands:
def bollinger_bands(candles: np.ndarray, period: int = 20, devup: float = 2, devdn: float = 2, matype: int = 0, devtype: int = 0,
source_type: str = "close",
sequential: bool = False) -> BollingerBands:
"""
BBANDS - Bollinger Bands
@@ -18,17 +22,27 @@ def bollinger_bands(candles: np.ndarray, period=20, devup=2, devdn=2, matype=0,
:param devup: float - default: 2
:param devdn: float - default: 2
:param matype: int - default: 0
:param devtype: int - default: 0
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: BollingerBands(upperband, middleband, lowerband)
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
upperbands, middlebands, lowerbands = talib.BBANDS(source, timeperiod=period, nbdevup=devup, nbdevdn=devdn,
matype=matype)
if devtype == 0:
dev = talib.STDDEV(source, period)
elif devtype == 1:
dev = mean_ad(source, period, sequential=True)
elif devtype == 2:
dev = median_ad(source, period, sequential=True)
middlebands = ma(source, period=period, matype=matype, sequential=True)
upperbands = middlebands + devup * dev
lowerbands = middlebands - devdn * dev
if sequential:
return BollingerBands(upperbands, middlebands, lowerbands)

View File

@@ -2,12 +2,17 @@ from typing import Union
import numpy as np
import talib
from jesse.indicators.ma import ma
from jesse.indicators.mean_ad import mean_ad
from jesse.indicators.median_ad import median_ad
from jesse.helpers import get_candle_source
from jesse.helpers import get_candle_source, slice_candles
def bollinger_bands_width(candles: np.ndarray, period=20, devup=2, devdn=2, matype=0, source_type="close",
sequential=False) -> Union[float, np.ndarray]:
def bollinger_bands_width(candles: np.ndarray, period: int = 20, devup: float = 2, devdn: float = 2, matype: int = 0,
devtype: int = 0,
source_type: str = "close",
sequential: bool = False) -> Union[float, np.ndarray]:
"""
BBW - Bollinger Bands Width - Bollinger Bands Bandwidth
@@ -16,19 +21,31 @@ def bollinger_bands_width(candles: np.ndarray, period=20, devup=2, devdn=2, maty
:param devup: float - default: 2
:param devdn: float - default: 2
:param matype: int - default: 0
:param devtype: int - default: 0
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
:return: BollingerBands(upperband, middleband, lowerband)
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
upperbands, middlebands, lowerbands = talib.BBANDS(source, timeperiod=period, nbdevup=devup, nbdevdn=devdn,
matype=matype)
if devtype == 0:
dev = talib.STDDEV(source, period)
elif devtype == 1:
dev = mean_ad(source, period, sequential=True)
elif devtype == 2:
dev = median_ad(source, period, sequential=True)
middlebands = ma(source, period=period, matype=matype, sequential=True)
upperbands = middlebands + devup * dev
lowerbands = middlebands - devdn * dev
if sequential:
return (upperbands - lowerbands) / middlebands
else:
return (upperbands[-1] - lowerbands[-1]) / middlebands[-1]

View File

@@ -3,22 +3,20 @@ from typing import Union
import numpy as np
import talib
from jesse.helpers import slice_candles
def bop(candles: np.ndarray, sequential=False) -> Union[float, np.ndarray]:
def bop(candles: np.ndarray, sequential: bool = False) -> Union[float, np.ndarray]:
"""
BOP - Balance Of Power
:param candles: np.ndarray
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
res = talib.BOP(candles[:, 1], candles[:, 3], candles[:, 4], candles[:, 2])
if sequential:
return res
else:
return None if np.isnan(res[-1]) else res[-1]
return res if sequential else res[-1]

View File

@@ -3,10 +3,12 @@ from typing import Union
import numpy as np
import talib
from jesse.helpers import get_candle_source
from jesse.helpers import get_candle_source, slice_candles
def cc(candles: np.ndarray, wma_period=10, roc_short_period=11, roc_long_period=14, source_type="close", sequential=False) -> Union[float, np.ndarray]:
def cc(candles: np.ndarray, wma_period: int = 10, roc_short_period: int = 11, roc_long_period: int = 14,
source_type: str = "close",
sequential: bool = False) -> Union[float, np.ndarray]:
"""
CC - Coppock Curve
@@ -15,14 +17,14 @@ def cc(candles: np.ndarray, wma_period=10, roc_short_period=11, roc_long_period=
:param roc_short_period: int - default: 11
:param roc_long_period: int - default: 14
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
res = talib.WMA(talib.ROC(source, timeperiod=roc_long_period) + talib.ROC(source, timeperiod=roc_short_period), timeperiod=wma_period)
res = talib.WMA(talib.ROC(source, timeperiod=roc_long_period) + talib.ROC(source, timeperiod=roc_short_period),
timeperiod=wma_period)
return res if sequential else res[-1]

View File

@@ -3,23 +3,21 @@ from typing import Union
import numpy as np
import talib
from jesse.helpers import slice_candles
def cci(candles: np.ndarray, period=14, sequential=False) -> Union[float, np.ndarray]:
def cci(candles: np.ndarray, period: int = 14, sequential: bool = False) -> Union[float, np.ndarray]:
"""
CCI - Commodity Channel Index
:param candles: np.ndarray
:param period: int - default=14
:param sequential: bool - default=False
:param period: int - default: 14
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
res = talib.CCI(candles[:, 3], candles[:, 4], candles[:, 2], timeperiod=period)
if sequential:
return res
else:
return None if np.isnan(res[-1]) else res[-1]
return res if sequential else res[-1]

34
jesse/indicators/cfo.py Normal file
View File

@@ -0,0 +1,34 @@
from typing import Union
import numpy as np
import talib
from jesse.helpers import get_candle_source
from jesse.helpers import slice_candles
def cfo(candles: np.ndarray, period: int = 14, scalar: float = 100, source_type: str = "close",
sequential: bool = False) -> Union[
float, np.ndarray]:
"""
CFO - Chande Forcast Oscillator
:param candles: np.ndarray
:param period: int - default: 14
:param scalar: float - default: 100
:param source_type: str - default: "close"
:param sequential: bool - default: False
:return: float | np.ndarray
"""
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
res = scalar * (source - talib.LINEARREG(source, timeperiod=period))
res /= source
if sequential:
return res
else:
return None if np.isnan(res[-1]) else res[-1]

46
jesse/indicators/cg.py Normal file
View File

@@ -0,0 +1,46 @@
from typing import Union
import numpy as np
try:
from numba import njit
except ImportError:
njit = lambda a : a
from jesse.helpers import get_candle_source, same_length, slice_candles
def cg(candles: np.ndarray, period: int = 10, source_type: str = "close", sequential: bool = False) -> Union[
float, np.ndarray]:
"""
Center of Gravity (CG)
:param candles: np.ndarray
:param period: int - default: 10
:param source_type: str - default: "close"
:param sequential: bool - default: False
:return: float | np.ndarray
"""
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
res = go_fast(source, period)
return same_length(candles, res) if sequential else res[-1]
@njit
def go_fast(source, period): # Function is compiled to machine code when called the first time
res = np.full_like(source, fill_value=np.nan)
for i in range(source.size):
if i > period:
num = 0
denom = 0
for count in range(period - 1):
close = source[i - count]
if not np.isnan(close):
num += (1 + count) * close
denom += close
result = -num / denom if denom != 0 else 0
res[i] = result
return res

View File

@@ -4,21 +4,23 @@ import numpy as np
import talib
from scipy.ndimage.filters import maximum_filter1d, minimum_filter1d
from jesse.helpers import slice_candles
def chande(candles: np.ndarray, period=22, mult=3.0, direction="long", sequential=False) -> Union[float, np.ndarray]:
def chande(candles: np.ndarray, period: int = 22, mult: float = 3.0, direction: str = "long",
sequential: bool = False) -> Union[float, np.ndarray]:
"""
Chandelier Exits
:param candles: np.ndarray
:param period: int - default: 22
:param period: float - default: 3.0
:param mult: float - default: 3.0
:param direction: str - default: "long"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
candles_close = candles[:, 2]
candles_high = candles[:, 3]
@@ -38,10 +40,10 @@ def chande(candles: np.ndarray, period=22, mult=3.0, direction="long", sequentia
return result if sequential else result[-1]
def filter1d_same(a, W, type, fillna=np.nan):
def filter1d_same(a: np.ndarray, W: int, max_or_min: str, fillna=np.nan):
out_dtype = np.full(0, fillna).dtype
hW = (W - 1) // 2 # Half window size
if type == 'max':
if max_or_min == 'max':
out = maximum_filter1d(a, size=W, origin=hW)
else:
out = minimum_filter1d(a, size=W, origin=hW)

36
jesse/indicators/chop.py Normal file
View File

@@ -0,0 +1,36 @@
from typing import Union
import numpy as np
import talib
from jesse.helpers import slice_candles
def chop(candles: np.ndarray, period: int = 14, scalar: float = 100, drift: int = 1, sequential: bool = False) -> Union[
float, np.ndarray]:
"""
Choppiness Index (CHOP)
:param candles: np.ndarray
:param period: int - default: 30
:param scalar: float - default: 100
:param drift: int - default: 1
:param sequential: bool - default: False
:return: float | np.ndarray
"""
candles = slice_candles(candles, sequential)
candles_close = candles[:, 2]
candles_high = candles[:, 3]
candles_low = candles[:, 4]
atr_sum = talib.SUM(talib.ATR(candles_high, candles_low, candles_close, timeperiod=drift), period)
hh = talib.MAX(candles_high, period)
ll = talib.MIN(candles_low, period)
res = (scalar * (np.log10(atr_sum) - np.log10(hh - ll))) / np.log10(period)
return res if sequential else res[-1]

41
jesse/indicators/cksp.py Normal file
View File

@@ -0,0 +1,41 @@
from collections import namedtuple
import numpy as np
import talib
from jesse.helpers import slice_candles
CKSP = namedtuple('CKSP', ['long', 'short'])
def cksp(candles: np.ndarray, p: int = 10, x: float = 1.0, q: int = 9, sequential: bool = False) -> CKSP:
"""
Chande Kroll Stop (CKSP)
:param candles: np.ndarray
:param p: int - default: 10
:param x: float - default: 1.0
:param q: int - default: 9
:param sequential: bool - default: False
:return: float | np.ndarray
"""
candles = slice_candles(candles, sequential)
candles_close = candles[:, 2]
candles_high = candles[:, 3]
candles_low = candles[:, 4]
atr = talib.ATR(candles_high, candles_low, candles_close, timeperiod=p)
LS0 = talib.MAX(candles_high, q) - x * atr
LS = talib.MAX(LS0, q)
SS0 = talib.MIN(candles_low, q) + x * atr
SS = talib.MIN(SS0, q)
if sequential:
return CKSP(LS, SS)
else:
return CKSP(LS[-1], SS[-1])

View File

@@ -4,26 +4,24 @@ import numpy as np
import talib
from jesse.helpers import get_candle_source
from jesse.helpers import slice_candles
def cmo(candles: np.ndarray, period=14, source_type="close", sequential=False) -> Union[float, np.ndarray]:
def cmo(candles: np.ndarray, period: int = 14, source_type: str = "close", sequential: bool = False) -> Union[
float, np.ndarray]:
"""
CMO - Chande Momentum Oscillator
:param candles: np.ndarray
:param period: int - default=14
:param period: int - default: 14
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
res = talib.CMO(source, timeperiod=period)
if sequential:
return res
else:
return None if np.isnan(res[-1]) else res[-1]
return res if sequential else res[-1]

View File

@@ -3,23 +3,21 @@ from typing import Union
import numpy as np
import talib
from jesse.helpers import slice_candles
def correl(candles: np.ndarray, period=5, sequential=False) -> Union[float, np.ndarray]:
def correl(candles: np.ndarray, period: int = 5, sequential: bool = False) -> Union[float, np.ndarray]:
"""
CORREL - Pearson's Correlation Coefficient (r)
:param candles: np.ndarray
:param period: int - default: 5
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
res = talib.CORREL(candles[:, 3], candles[:, 4], timeperiod=period)
if sequential:
return res
else:
return None if np.isnan(res[-1]) else res[-1]
return res if sequential else res[-1]

View File

@@ -1,14 +1,18 @@
import math
from collections import namedtuple
import numpy as np
try:
from numba import njit
except ImportError:
njit = lambda a : a
from jesse.helpers import get_candle_source, np_shift
from jesse.helpers import get_candle_source, np_shift, slice_candles
CC = namedtuple('CC', ['real', 'imag', 'angle', 'state'])
def correlation_cycle(candles: np.ndarray, period=20, threshold=9, source_type="close", sequential=False) -> CC:
def correlation_cycle(candles: np.ndarray, period: int = 20, threshold: int = 9, source_type: str = "close",
sequential: bool = False) -> CC:
"""
"Correlation Cycle, Correlation Angle, Market State - John Ehlers
@@ -16,17 +20,32 @@ def correlation_cycle(candles: np.ndarray, period=20, threshold=9, source_type="
:param period: int - default: 20
:param threshold: int - default: 9
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: CC(real, imag)
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
realPart, imagPart, angle = go_fast(source, period)
priorAngle = np_shift(angle, 1, fill_value=np.nan)
angle = np.where(np.logical_and(priorAngle > angle, priorAngle - angle < 270.0), priorAngle, angle)
# Market State Function
state = np.where(np.abs(angle - priorAngle) < threshold, np.where(angle >= 0.0, 1, np.where(angle < 0.0, -1, 0)), 0)
if sequential:
return CC(realPart, imagPart, angle, state)
else:
return CC(realPart[-1], imagPart[-1], angle[-1], state[-1])
@njit
def go_fast(source, period): # Function is compiled to machine code when called the first time
# Correlation Cycle Function
PIx2 = 4.0 * math.asin(1.0)
PIx2 = 4.0 * np.arcsin(1.0)
period = max(2, period)
realPart = np.full_like(source, np.nan)
@@ -46,45 +65,34 @@ def correlation_cycle(candles: np.ndarray, period=20, threshold=9, source_type="
for j in range(period):
jMinusOne = j + 1
if np.isnan(source[i - jMinusOne]):
X = 0
else:
X = source[i - jMinusOne]
X = 0 if np.isnan(source[i - jMinusOne]) else source[i - jMinusOne]
temp = PIx2 * jMinusOne / period
Yc = np.cos(temp)
Ys = -np.sin(temp)
Rx = Rx + X
Ix = Ix + X
Rxx = Rxx + X * X
Ixx = Ixx + X * X
Rxy = Rxy + X * Yc
Ixy = Ixy + X * Ys
Ryy = Ryy + Yc * Yc
Iyy = Iyy + Ys * Ys
Ry = Ry + Yc
Iy = Iy + Ys
Rx += X
Ix += X
Rxx += X * X
Ixx += X * X
Rxy += X * Yc
Ixy += X * Ys
Ryy += Yc * Yc
Iyy += Ys * Ys
Ry += Yc
Iy += Ys
temp_1 = period * Rxx - Rx * Rx
temp_2 = period * Ryy - Ry * Ry
if (temp_1 > 0.0 and temp_2 > 0.0):
temp_1 = period * Rxx - Rx**2
temp_2 = period * Ryy - Ry**2
if temp_1 > 0.0 and temp_2 > 0.0:
realPart[i] = (period * Rxy - Rx * Ry) / np.sqrt(temp_1 * temp_2)
temp_1 = period * Ixx - Ix * Ix
temp_2 = period * Iyy - Iy * Iy
if (temp_1 > 0.0 and temp_2 > 0.0):
temp_1 = period * Ixx - Ix**2
temp_2 = period * Iyy - Iy**2
if temp_1 > 0.0 and temp_2 > 0.0:
imagPart[i] = (period * Ixy - Ix * Iy) / np.sqrt(temp_1 * temp_2)
# Correlation Angle Phasor
HALF_OF_PI = math.asin(1.0)
HALF_OF_PI = np.arcsin(1.0)
angle = np.where(imagPart == 0, 0.0, np.degrees(np.arctan(realPart / imagPart) + HALF_OF_PI))
angle = np.where(imagPart > 0.0, angle - 180.0, angle)
priorAngle = np_shift(angle, 1, fill_value=np.nan)
angle = np.where(np.logical_and(priorAngle > angle, priorAngle - angle < 270.0), priorAngle, angle)
# Market State Function
state = np.where(np.abs(angle - priorAngle) < threshold, np.where(angle >= 0.0, 1, np.where(angle < 0.0, -1, 0)), 0)
if sequential:
return CC(realPart, imagPart, angle, state)
else:
return CC(realPart[-1], imagPart[-1], angle[-1], state[-1])
return realPart, imagPart, angle

View File

@@ -3,20 +3,21 @@ from typing import Union
import numpy as np
import tulipy as ti
from jesse.helpers import slice_candles, same_length
def cvi(candles: np.ndarray, period=5, sequential=False) -> Union[float, np.ndarray]:
def cvi(candles: np.ndarray, period: int = 5, sequential: bool = False) -> Union[float, np.ndarray]:
"""
CVI - Chaikins Volatility
:param candles: np.ndarray
:param period: int - default: 5
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
res = ti.cvi(np.ascontiguousarray(candles[:, 3]), np.ascontiguousarray(candles[:, 4]), period=period)
return np.concatenate((np.full((candles.shape[0] - res.shape[0]), np.nan), res), axis=0) if sequential else res[-1]
return same_length(candles, res) if sequential else res[-1]

49
jesse/indicators/cwma.py Normal file
View File

@@ -0,0 +1,49 @@
from typing import Union
import numpy as np
try:
from numba import njit
except ImportError:
njit = lambda a : a
from jesse.helpers import get_candle_source, slice_candles
def cwma(candles: np.ndarray, period: int = 14, source_type: str = "close", sequential: bool = False) -> Union[
float, np.ndarray]:
"""
Cubed Weighted Moving Average
:param candles: np.ndarray
:param period: int - default: 14
:param source_type: str - default: "close"
:param sequential: bool - default: False
:return: float | np.ndarray
"""
# Accept normal array too.
if len(candles.shape) == 1:
source = candles
else:
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
res = vpwma_fast(source, period)
return res if sequential else res[-1]
@njit
def vpwma_fast(source, period):
newseries = np.copy(source)
for j in range(period + 1, source.shape[0]):
my_sum = 0.0
weightSum = 0.0
for i in range(period - 1):
weight = np.power(period - i, 3)
my_sum += (source[j - i] * weight)
weightSum += weight
newseries[j] = my_sum / weightSum
return newseries

View File

@@ -1,49 +1,61 @@
import talib
from collections import namedtuple
import numpy as np
import talib
try:
from numba import njit
except ImportError:
njit = lambda a : a
from jesse.helpers import get_candle_source
from jesse.helpers import slice_candles
DamianiVolatmeter = namedtuple('DamianiVolatmeter', ['vol', 'anti' ])
DamianiVolatmeter = namedtuple('DamianiVolatmeter', ['vol', 'anti'])
def damiani_volatmeter(candles: np.ndarray, vis_atr=13, vis_std=20, sed_atr=40, sed_std=100, threshold=1.4, source_type="close", sequential=False) -> DamianiVolatmeter:
def damiani_volatmeter(candles: np.ndarray, vis_atr: int = 13, vis_std: int = 20, sed_atr: int = 40, sed_std: int = 100,
threshold: float = 1.4, source_type: str = "close",
sequential: bool = False) -> DamianiVolatmeter:
"""
Damiani Volatmeter
:param candles: np.ndarray
:param vis_atr: int - default=13
:param vis_std: int - default=20
:param sed_atr: int - default=40
:param sed_std: int - default=100
:param threshold: float - default=1.4
:param vis_atr: int - default: 13
:param vis_std: int - default: 20
:param sed_atr: int - default: 40
:param sed_std: int - default: 100
:param threshold: float - default: 1.4
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
lag_s = 0.5
vol = np.full_like(source, 0)
t = np.full_like(source, 0)
atrvis = talib.ATR(candles[:, 3], candles[:, 4], candles[:, 2], timeperiod=vis_atr)
atrsed = talib.ATR(candles[:, 3], candles[:, 4], candles[:, 2], timeperiod=sed_atr)
for i in range(source.shape[0]):
if not (i < sed_std):
vol[i]=atrvis[i] / atrsed[i] + lag_s * (vol[i - 1] - vol[i - 3])
anti_thres = np.std(source[i - vis_std:i]) / np.std(source[i - sed_std:i])
t[i] = threshold - anti_thres
vol, t = damiani_volatmeter_fast(source, sed_std, atrvis, atrsed, vis_std, threshold)
if sequential:
return DamianiVolatmeter(vol, t)
else:
return DamianiVolatmeter(vol[-1], t[-1])
@njit
def damiani_volatmeter_fast(source, sed_std, atrvis, atrsed, vis_std,
threshold): # Function is compiled to machine code when called the first time
lag_s = 0.5
vol = np.full_like(source, 0)
t = np.full_like(source, 0)
for i in range(source.shape[0]):
if i >= sed_std:
vol[i] = atrvis[i] / atrsed[i] + lag_s * (vol[i - 1] - vol[i - 3])
anti_thres = np.std(source[i - vis_std:i]) / np.std(source[i - sed_std:i])
t[i] = threshold - anti_thres
return vol, t

View File

@@ -2,46 +2,31 @@ from typing import Union
import numpy as np
from jesse.helpers import get_candle_source
from jesse.helpers import get_candle_source, slice_candles
from .high_pass_2_pole import high_pass_2_pole_fast
def dec_osc(candles: np.ndarray, hp_period=125, k=1, source_type="close", sequential=False) -> Union[float, np.ndarray]:
def dec_osc(candles: np.ndarray, hp_period: int = 125, k: float = 1, source_type: str = "close",
sequential: bool = False) -> Union[float, np.ndarray]:
"""
Ehlers Decycler Oscillator
:param candles: np.ndarray
:param hp_period: int - default=125
:param k: float - default=1
:param sequential: bool - default=False
:param hp_period: int - default: 125
:param k: float - default: 1
:param source_type: str - default: "close"
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
alphaArg1 = 2 * np.pi * 0.707 / hp_period
alpha1 = (np.cos(alphaArg1) + np.sin(alphaArg1) - 1) / np.cos(alphaArg1)
coeff1 = np.array([(1 - alpha1 / 2) ** 2, 2 * (1 - alpha1), -(1 - alpha1) ** 2])
hp1 = np.copy(source)
alphaArg2 = 2 * np.pi * 0.707 / (0.5 * hp_period)
alpha2 = (np.cos(alphaArg2) + np.sin(alphaArg2) - 1) / np.cos(alphaArg2)
coeff2 = np.array([(1 - alpha2 / 2) ** 2, 2 * (1 - alpha2), -(1 - alpha2) ** 2])
hp2 = np.copy(source)
hp = high_pass_2_pole_fast(source, hp_period)
dec = source - hp
decosc = high_pass_2_pole_fast(dec, 0.5 * hp_period)
for i in range(source.shape[0]):
val1 = np.array([source[i] - 2 * source[i - 1] + source[i - 2], hp1[i - 1], hp1[i - 2]])
hp1[i] = np.matmul(coeff1, val1)
res = 100 * k * decosc / source
val2 = np.array(
[(source[i] - hp1[i]) - 2 * (source[i - 1] - hp1[i - 1]) + (source[i - 2] - hp1[i - 2]), hp2[i - 1],
hp2[i - 2]])
hp2[i] = np.matmul(coeff2, val2)
res = 100 * k * hp2 / source
if sequential:
return res
else:
return None if np.isnan(res[-1]) else res[-1]
return res if sequential else res[-1]

View File

@@ -2,35 +2,26 @@ from typing import Union
import numpy as np
from jesse.helpers import get_candle_source
from jesse.helpers import get_candle_source, slice_candles
from .high_pass_2_pole import high_pass_2_pole_fast
def decycler(candles: np.ndarray, hp_period=125, source_type="close", sequential=False) -> Union[float, np.ndarray]:
def decycler(candles: np.ndarray, hp_period: int = 125, source_type: str = "close", sequential: bool = False) -> Union[
float, np.ndarray]:
"""
Ehlers Simple Decycler
:param candles: np.ndarray
:param hp_period: int - default=125
:param sequential: bool - default=False
:param hp_period: int - default: 125
:param source_type: str - default: "close"
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
alphaArg1 = 2 * np.pi * 0.707 / hp_period
alpha1 = (np.cos(alphaArg1) + np.sin(alphaArg1) - 1) / np.cos(alphaArg1)
coeff1 = np.array([(1 - alpha1 / 2) ** 2, 2 * (1 - alpha1), -(1 - alpha1) ** 2])
hp1 = np.copy(source)
hp = high_pass_2_pole_fast(source, hp_period)
res = source - hp
for i in range(source.shape[0]):
val1 = np.array([source[i] - 2 * source[i - 1] + source[i - 2], hp1[i - 1], hp1[i - 2]])
hp1[i] = np.matmul(coeff1, val1)
res = source - hp1
if sequential:
return res
else:
return None if np.isnan(res[-1]) else res[-1]
return res if sequential else res[-1]

View File

@@ -3,24 +3,27 @@ from typing import Union
import numpy as np
import talib
from jesse.helpers import get_candle_source
from jesse.helpers import get_candle_source, slice_candles
def dema(candles: np.ndarray, period=30, source_type="close", sequential=False) -> Union[float, np.ndarray]:
def dema(candles: np.ndarray, period: int = 30, source_type: str = "close", sequential: bool = False) -> Union[
float, np.ndarray]:
"""
DEMA - Double Exponential Moving Average
:param candles: np.ndarray
:param period: int - default: 30
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
if len(candles.shape) == 1:
source = candles
else:
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
source = get_candle_source(candles, source_type=source_type)
res = talib.DEMA(source, timeperiod=period)
return res if sequential else res[-1]

View File

@@ -0,0 +1,45 @@
from typing import Union
import numpy as np
import talib
from jesse.indicators.mean_ad import mean_ad
from jesse.indicators.median_ad import median_ad
from jesse.helpers import slice_candles
def devstop(candles: np.ndarray, period: int = 20, mult: float = 0, devtype: int = 0, direction: str = "long",
sequential: bool = False) -> Union[
float, np.ndarray]:
"""
Kase Dev Stops
:param candles: np.ndarray
:param period: int - default: 20
:param mult: float - default: 0
:param devtype: int - default: 0
:param direction: str - default: long
:param sequential: bool - default: False
:return: float | np.ndarray
"""
candles = slice_candles(candles, sequential)
high = candles[:, 3]
low = candles[:, 4]
AVTR = talib.SMA(talib.MAX(high, 2) - talib.MIN(low, 2), period)
if devtype == 0:
SD = talib.STDDEV(talib.MAX(high, 2) - talib.MIN(low, 2), period)
elif devtype == 1:
SD = mean_ad(talib.MAX(high, 2) - talib.MIN(low, 2), period, sequential=True)
elif devtype == 2:
SD = median_ad(talib.MAX(high, 2) - talib.MIN(low, 2), period, sequential=True)
if direction == "long":
res = talib.MAX(high - AVTR - mult * SD, period)
else:
res = talib.MIN(low + AVTR + mult * SD, period)
return res if sequential else res[-1]

View File

@@ -3,21 +3,22 @@ from collections import namedtuple
import numpy as np
import talib
from jesse.helpers import slice_candles
DI = namedtuple('DI', ['plus', 'minus'])
def di(candles: np.ndarray, period=14, sequential=False) -> DI:
def di(candles: np.ndarray, period: int = 14, sequential: bool = False) -> DI:
"""
DI - Directional Indicator
:param candles: np.ndarray
:param period: int - default=14
:param sequential: bool - default=False
:param period: int - default: 14
:param sequential: bool - default: False
:return: DI(plus, minus)
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
MINUS_DI = talib.MINUS_DI(candles[:, 3], candles[:, 4], candles[:, 2], timeperiod=period)
PLUS_DI = talib.PLUS_DI(candles[:, 3], candles[:, 4], candles[:, 2], timeperiod=period)

View File

@@ -3,24 +3,25 @@ from collections import namedtuple
import numpy as np
import talib
from jesse.helpers import slice_candles
DM = namedtuple('DM', ['plus', 'minus'])
def dm(candles: np.ndarray, period=14, sequential=False) -> DM:
def dm(candles: np.ndarray, period: int = 14, sequential: bool = False) -> DM:
"""
DM - Directional Movement
:param candles: np.ndarray
:param period: int - default=14
:param sequential: bool - default=False
:param period: int - default: 14
:param sequential: bool - default: False
:return: DM(plus, minus)
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
MINUS_DI = talib.MINUS_DM(candles[:, 3], candles[:, 4], timeperiod=period)
PLUS_DI = talib.PLUS_DM(candles[:, 3], candles[:, 4], timeperiod=period)
MINUS_DI = talib.MINUS_DM(candles[:, 3], candles[:, 4], timeperiod=period)
PLUS_DI = talib.PLUS_DM(candles[:, 3], candles[:, 4], timeperiod=period)
if sequential:
return DM(PLUS_DI, MINUS_DI)

View File

@@ -3,21 +3,22 @@ from collections import namedtuple
import numpy as np
import talib
from jesse.helpers import slice_candles
DonchianChannel = namedtuple('DonchianChannel', ['upperband', 'middleband', 'lowerband'])
def donchian(candles: np.ndarray, period=20, sequential=False) -> DonchianChannel:
def donchian(candles: np.ndarray, period: int = 20, sequential: bool = False) -> DonchianChannel:
"""
Donchian Channels
:param candles: np.ndarray
:param period: int - default: 20
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: DonchianChannel(upperband, middleband, lowerband)
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
UC = talib.MAX(candles[:, 3], timeperiod=period)
LC = talib.MIN(candles[:, 4], timeperiod=period)

View File

@@ -3,24 +3,24 @@ from typing import Union
import numpy as np
import tulipy as ti
from jesse.helpers import get_candle_source
from jesse.helpers import get_candle_source, same_length, slice_candles
def dpo(candles: np.ndarray, period=5, source_type="close", sequential=False) -> Union[float, np.ndarray]:
def dpo(candles: np.ndarray, period: int = 5, source_type: str = "close", sequential: bool = False) -> Union[
float, np.ndarray]:
"""
DPO - Detrended Price Oscillator
:param candles: np.ndarray
:param period: int - default: 5
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
res = ti.dpo(np.ascontiguousarray(source), period=period)
return np.concatenate((np.full((candles.shape[0] - res.shape[0]), np.nan), res), axis=0) if sequential else res[-1]
return same_length(candles, res) if sequential else res[-1]

View File

@@ -4,22 +4,23 @@ import numpy as np
import talib
import jesse.helpers as jh
from jesse.helpers import slice_candles
def dti(candles: np.ndarray, r=14, s=10, u=5, sequential=False) -> Union[float, np.ndarray]:
def dti(candles: np.ndarray, r: int = 14, s: int = 10, u: int = 5, sequential: bool = False) -> Union[
float, np.ndarray]:
"""
DTI by William Blau
:param candles: np.ndarray
:param r: int - default=14
:param s: int - default=10
:param u: int - default=5
:param sequential: bool - default=False
:param r: int - default: 14
:param s: int - default: 10
:param u: int - default: 5
:param sequential: bool - default: False
:return: float
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
high = candles[:, 3]
low = candles[:, 4]

View File

@@ -3,20 +3,20 @@ from typing import Union
import numpy as np
import talib
from jesse.helpers import slice_candles
def dx(candles: np.ndarray, period=14, sequential=False) -> Union[float, np.ndarray]:
def dx(candles: np.ndarray, period: int = 14, sequential: bool = False) -> Union[float, np.ndarray]:
"""
DX - Directional Movement Index
:param candles: np.ndarray
:param period: int - default: 14
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
res = talib.DX(candles[:, 3], candles[:, 4], candles[:, 2], timeperiod=period)

53
jesse/indicators/edcf.py Normal file
View File

@@ -0,0 +1,53 @@
from typing import Union
import numpy as np
try:
from numba import njit
except ImportError:
njit = lambda a: a
from jesse.helpers import get_candle_source, slice_candles
def edcf(candles: np.ndarray, period: int = 15, source_type: str = "hl2", sequential: bool = False) -> Union[
float, np.ndarray]:
"""
Ehlers Distance Coefficient Filter
:param candles: np.ndarray
:param period: int - default: 15
:param source_type: str - default: "close"
:param sequential: bool - default: False
:return: float | np.ndarray
"""
# Accept normal array too.
if len(candles.shape) == 1:
source = candles
else:
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
res = edcf_fast(source, period)
return res if sequential else res[-1]
@njit
def edcf_fast(source, period):
newseries = np.full_like(source, np.nan)
for j in range(2 * period, source.shape[0]):
num = 0.0
coefSum = 0.0
for i in range(period):
distance = 0.0
for lb in range(1, period):
distance += np.power(source[j - i] - source[j - i - lb], 2)
num += distance * source[j - i]
coefSum += distance
newseries[j] = num / coefSum if coefSum != 0 else 0
return newseries

View File

@@ -2,31 +2,41 @@ from typing import Union
import numpy as np
import talib
try:
from numba import njit
except ImportError:
njit = lambda a : a
from jesse.helpers import get_candle_source
from jesse.helpers import get_candle_source, same_length, slice_candles
def efi(candles: np.ndarray, period=13, source_type="close", sequential=False) -> Union[float, np.ndarray]:
def efi(candles: np.ndarray, period: int = 13, source_type: str = "close", sequential: bool = False) -> Union[
float, np.ndarray]:
"""
EFI - Elders Force Index
:param candles: np.ndarray
:param period: int - default: 13
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
dif = np.zeros(len(source) - 1)
for i in range(1, len(source)):
dif[i - 1] = (source[i] - source[i - 1]) * candles[:, 5][i]
dif = efi_fast(source, candles[:, 5])
res = talib.EMA(dif, timeperiod=period)
res_with_nan = np.concatenate((np.full((candles.shape[0] - res.shape[0]), np.nan), res))
res_with_nan = same_length(candles, res)
return res_with_nan if sequential else res_with_nan[-1]
@njit
def efi_fast(source, volume):
dif = np.zeros(source.size - 1)
for i in range(1, source.size):
dif[i - 1] = (source[i] - source[i - 1]) * volume[i]
return dif

View File

@@ -3,24 +3,27 @@ from typing import Union
import numpy as np
import talib
from jesse.helpers import get_candle_source
from jesse.helpers import get_candle_source, slice_candles
def ema(candles: np.ndarray, period=5, source_type="close", sequential=False) -> Union[float, np.ndarray]:
def ema(candles: np.ndarray, period: int = 5, source_type: str = "close", sequential: bool = False) -> Union[
float, np.ndarray]:
"""
EMA - Exponential Moving Average
:param candles: np.ndarray
:param period: int - default: 5
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
if len(candles.shape) == 1:
source = candles
else:
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
source = get_candle_source(candles, source_type=source_type)
res = talib.EMA(source, timeperiod=period)
return res if sequential else res[-1]

View File

@@ -1,32 +1,53 @@
import math
from collections import namedtuple
import numpy as np
import talib
try:
from numba import njit
except ImportError:
njit = lambda a : a
from jesse.helpers import slice_candles
EMD = namedtuple('EMD', ['upperband', 'middleband', 'lowerband'])
def emd(candles: np.ndarray, period=20, delta=0.5, fraction=0.1, sequential=False) -> EMD:
def emd(candles: np.ndarray, period: int = 20, delta=0.5, fraction=0.1, sequential: bool = False) -> EMD:
"""
Empirical Mode Decomposition by John F. Ehlers and Ric Way
:param candles: np.ndarray
:param period: int - default=20
:param delta: float - default=0.5
:param fraction: float - default=0.1
:param sequential: bool - default=False
:param period: int - default: 20
:param delta: float - default: 0.5
:param fraction: float - default: 0.1
:param sequential: bool - default: False
:return: EMD(upperband, middleband, lowerband)
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
price = (candles[:, 3] + candles[:, 4]) / 2
bp = bp_fast(price, period, delta)
mean = talib.SMA(bp, timeperiod=2 * period)
peak, valley = peak_valley_fast(bp, price)
avg_peak = fraction * talib.SMA(peak, timeperiod=50)
avg_valley = fraction * talib.SMA(valley, timeperiod=50)
if sequential:
return EMD(avg_peak, mean, avg_valley)
else:
return EMD(avg_peak[-1], mean[-1], avg_valley[-1])
@njit
def bp_fast(price, period, delta):
# bandpass filter
beta = math.cos(2 * math.pi / period)
gamma = 1 / math.cos(4 * math.pi * delta / period)
alpha = gamma - math.sqrt(gamma * gamma - 1)
beta = np.cos(2 * np.pi / period)
gamma = 1 / np.cos(4 * np.pi * delta / period)
alpha = gamma - np.sqrt(gamma * gamma - 1)
bp = np.zeros_like(price)
for i in range(price.shape[0]):
@@ -34,9 +55,11 @@ def emd(candles: np.ndarray, period=20, delta=0.5, fraction=0.1, sequential=Fals
bp[i] = 0.5 * (1 - alpha) * (price[i] - price[i - 2]) + beta * (1 + alpha) * bp[i - 1] - alpha * bp[i - 2]
else:
bp[i] = 0.5 * (1 - alpha) * (price[i] - price[i - 2])
return bp
mean = talib.SMA(bp, timeperiod=2 * period)
@njit
def peak_valley_fast(bp, price):
peak = np.copy(bp)
valley = np.copy(bp)
@@ -49,10 +72,4 @@ def emd(candles: np.ndarray, period=20, delta=0.5, fraction=0.1, sequential=Fals
if bp[i - 1] < bp[i] and bp[i - 1] < bp[i - 2]:
valley[i] = bp[i - 1]
avg_peak = fraction * talib.SMA(peak, timeperiod=50)
avg_valley = fraction * talib.SMA(valley, timeperiod=50)
if sequential:
return EMD(avg_peak, mean, avg_valley)
else:
return EMD(avg_peak[-1], mean[-1], avg_valley[-1])
return peak, valley

View File

@@ -3,20 +3,21 @@ from typing import Union
import numpy as np
import tulipy as ti
from jesse.helpers import slice_candles, same_length
def emv(candles: np.ndarray, sequential=False) -> Union[float, np.ndarray]:
def emv(candles: np.ndarray, sequential: bool = False) -> Union[float, np.ndarray]:
"""
EMV - Ease of Movement
:param candles: np.ndarray
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
res = ti.emv(np.ascontiguousarray(candles[:, 3]), np.ascontiguousarray(candles[:, 4]), np.ascontiguousarray(candles[:, 5]))
res = ti.emv(np.ascontiguousarray(candles[:, 3]), np.ascontiguousarray(candles[:, 4]),
np.ascontiguousarray(candles[:, 5]))
return np.concatenate((np.full((candles.shape[0] - res.shape[0]), np.nan), res), axis=0) if sequential else res[-1]
return same_length(candles, res) if sequential else res[-1]

50
jesse/indicators/epma.py Normal file
View File

@@ -0,0 +1,50 @@
from typing import Union
import numpy as np
try:
from numba import njit
except ImportError:
njit = lambda a : a
from jesse.helpers import get_candle_source, slice_candles
def epma(candles: np.ndarray, period: int = 11, offset: int = 4, source_type: str = "close", sequential: bool = False) -> Union[
float, np.ndarray]:
"""
End Point Moving Average
:param candles: np.ndarray
:param period: int - default: 14
:param offset: int - default: 4
:param source_type: str - default: "close"
:param sequential: bool - default: False
:return: float | np.ndarray
"""
# Accept normal array too.
if len(candles.shape) == 1:
source = candles
else:
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
res = epma_fast(source, period, offset)
return res if sequential else res[-1]
@njit
def epma_fast(source, period, offset):
newseries = np.copy(source)
for j in range(period + offset + 1 , source.shape[0]):
my_sum = 0.0
weightSum = 0.0
for i in range(period - 1):
weight = period - i - offset
my_sum += (source[j - i] * weight)
weightSum += weight
newseries[j] = 1 / weightSum * my_sum
return newseries

32
jesse/indicators/er.py Normal file
View File

@@ -0,0 +1,32 @@
from typing import Union
import numpy as np
from numpy.lib.stride_tricks import sliding_window_view
from jesse.helpers import get_candle_source, slice_candles, same_length
def er(candles: np.ndarray, period: int = 5, source_type: str = "close", sequential: bool = False) -> Union[
float, np.ndarray]:
"""
ER - The Kaufman Efficiency indicator
:param candles: np.ndarray
:param period: int - default: 5
:param source_type: str - default: "close"
:param sequential: bool - default: False
:return: float | np.ndarray
"""
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
change = np.abs(np.diff(source, period))
abs_dif = np.abs(np.diff(source))
swv = sliding_window_view(abs_dif, window_shape=period)
volatility = swv.sum()
res = change / volatility
return same_length(candles, res) if sequential else res[-1]

35
jesse/indicators/eri.py Normal file
View File

@@ -0,0 +1,35 @@
from collections import namedtuple
import numpy as np
from jesse.indicators.ma import ma
from jesse.helpers import get_candle_source, slice_candles
ERI = namedtuple('ERI', ['bull', 'bear'])
def eri(candles: np.ndarray, period: int = 13, matype: int = 1, source_type: str = "close",
sequential: bool = False) -> ERI:
"""
Elder Ray Index (ERI)
:param candles: np.ndarray
:param period: int - default: 13
:param matype: int - default: 1
:param source_type: str - default: "close"
:param sequential: bool - default: False
:return: float | np.ndarray
"""
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
ema = ma(source, period=period, matype=matype, sequential=True)
bull = candles[:, 3] - ema
bear = candles[:, 4] - ema
if sequential:
return ERI(bull, bear)
else:
return ERI(bull[-1], bear[-1])

View File

@@ -3,28 +3,27 @@ from collections import namedtuple
import numpy as np
import tulipy as ti
from jesse.helpers import slice_candles, same_length
FisherTransform = namedtuple('FisherTransform', ['fisher', 'signal'])
def fisher(candles: np.ndarray, period=9, sequential=False) -> FisherTransform:
def fisher(candles: np.ndarray, period: int = 9, sequential: bool = False) -> FisherTransform:
"""
The Fisher Transform helps identify price reversals.
:param candles: np.ndarray
:param period: int - default: 9
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: FisherTransform(fisher, signal)
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
fisher, fisher_signal = ti.fisher(np.ascontiguousarray(candles[:, 3]), np.ascontiguousarray(candles[:, 4]),
period=period)
fisher_val, fisher_signal = ti.fisher(np.ascontiguousarray(candles[:, 3]), np.ascontiguousarray(candles[:, 4]),
period=period)
if sequential:
return FisherTransform(np.concatenate((np.full((candles.shape[0] - fisher.shape[0]), np.nan), fisher), axis=0),
np.concatenate(
(np.full((candles.shape[0] - fisher_signal.shape[0]), np.nan), fisher_signal)))
return FisherTransform(same_length(candles, fisher_val), same_length(candles, fisher_signal))
else:
return FisherTransform(fisher[-1], fisher_signal[-1])
return FisherTransform(fisher_val[-1], fisher_signal[-1])

View File

@@ -3,24 +3,24 @@ from typing import Union
import numpy as np
import tulipy as ti
from jesse.helpers import get_candle_source
from jesse.helpers import get_candle_source, same_length, slice_candles
def fosc(candles: np.ndarray, period=5, source_type="close", sequential=False) -> Union[float, np.ndarray]:
def fosc(candles: np.ndarray, period: int = 5, source_type: str = "close", sequential: bool = False) -> Union[
float, np.ndarray]:
"""
FOSC - Forecast Oscillator
:param candles: np.ndarray
:param period: int - default: 5
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
res = ti.fosc(np.ascontiguousarray(source), period=period)
return np.concatenate((np.full((candles.shape[0] - res.shape[0]), np.nan), res), axis=0) if sequential else res[-1]
return same_length(candles, res) if sequential else res[-1]

View File

@@ -1,10 +1,16 @@
import math
from typing import Union
import numpy as np
try:
from numba import njit
except ImportError:
njit = lambda a : a
from jesse.helpers import slice_candles
def frama(candles: np.ndarray, window=10, FC=1, SC=300, sequential=False) -> Union[float, np.ndarray]:
def frama(candles: np.ndarray, window: int = 10, FC: int = 1, SC: int = 300, sequential: bool = False) -> Union[
float, np.ndarray]:
"""
Fractal Adaptive Moving Average (FRAMA)
@@ -12,13 +18,11 @@ def frama(candles: np.ndarray, window=10, FC=1, SC=300, sequential=False) -> Uni
:param window: int - default: 10
:param FC: int - default: 1
:param SC: int - default: 300
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
n = window
@@ -27,35 +31,43 @@ def frama(candles: np.ndarray, window=10, FC=1, SC=300, sequential=False) -> Uni
print("FRAMA n must be even. Adding one")
n += 1
w = math.log(2.0 / (SC + 1))
res = frame_fast(candles, n, SC, FC)
D = np.zeros(len(candles))
if sequential:
return res
else:
return res[-1]
@njit
def frame_fast(candles, n, SC, FC):
w = np.log(2.0 / (SC + 1))
D = np.zeros(candles.size)
D[:n] = np.NaN
alphas = np.zeros(len(candles))
alphas = np.zeros(candles.size)
alphas[:n] = np.NaN
for i in range(n, len(candles)):
for i in range(n, candles.shape[0]):
per = candles[i - n:i]
# take 2 batches of the input
split = np.split(per, 2)
v1 = split[0]
v2 = split[1]
v1 = per[per.shape[0] // 2:]
v2 = per[:per.shape[0] // 2]
N1 = (np.max(v1[:, 3]) - np.min(v1[:, 4])) / (n / 2)
N2 = (np.max(v2[:, 3]) - np.min(v2[:, 4])) / (n / 2)
N3 = (np.max(per[:, 3]) - np.min(per[:, 4])) / n
N1 = (max(v1[:, 3]) - min(v1[:, 4])) / (n / 2)
N2 = (max(v2[:, 3]) - min(v2[:, 4])) / (n / 2)
N3 = (max(per[:, 3]) - min(per[:, 4])) / n
if N1 > 0 and N2 > 0 and N3 > 0:
D[i] = (math.log(N1 + N2) - math.log(N3)) / math.log(2)
D[i] = (np.log(N1 + N2) - np.log(N3)) / np.log(2)
else:
D[i] = D[i - 1]
oldalpha = math.exp(w * (D[i] - 1))
oldalpha = np.exp(w * (D[i] - 1))
# keep btwn 1 & 0.01
oldalpha = np.max([oldalpha, 0.1])
oldalpha = np.min([oldalpha, 1])
oldalpha = max([oldalpha, 0.1])
oldalpha = min([oldalpha, 1])
oldN = (2 - oldalpha) / oldalpha
N = ((SC - FC) * ((oldN - 1) / (SC - 1))) + FC
@@ -67,14 +79,10 @@ def frama(candles: np.ndarray, window=10, FC=1, SC=300, sequential=False) -> Uni
else:
alphas[i] = alpha_
frama = np.zeros(len(candles))
frama[n - 1] = np.mean(candles[:, 2][:n])
frama[:n - 1] = np.NaN
frama_val = np.zeros(candles.shape[0])
frama_val[n - 1] = np.mean(candles[:, 2][:n])
frama_val[:n - 1] = np.NaN
for i in range(n, len(frama)):
frama[i] = (alphas[i] * candles[:, 2][i]) + (1 - alphas[i]) * frama[i - 1]
if sequential:
return frama
else:
return frama[-1]
for i in range(n, frama_val.shape[0]):
frama_val[i] = (alphas[i] * candles[:, 2][i]) + (1 - alphas[i]) * frama_val[i - 1]
return frama_val

54
jesse/indicators/fwma.py Normal file
View File

@@ -0,0 +1,54 @@
from math import fabs
from typing import Union
import numpy as np
from numpy.lib.stride_tricks import sliding_window_view
from jesse.helpers import get_candle_source, slice_candles, same_length
def fwma(candles: np.ndarray, period: int = 5, source_type: str = "close", sequential: bool = False) -> Union[
float, np.ndarray]:
"""
Fibonacci's Weighted Moving Average (FWMA)
:param candles: np.ndarray
:param period: int - default: 5
:param source_type: str - default: "close"
:param sequential: bool - default: False
:return: float | np.ndarray
"""
# Accept normal array too.
if len(candles.shape) == 1:
source = candles
else:
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
fibs = fibonacci(n=period)
swv = sliding_window_view(source, window_shape=period)
res = np.average(swv, weights=fibs, axis=-1)
return same_length(candles, res) if sequential else res[-1]
def fibonacci(n: int = 2) -> np.ndarray:
"""Fibonacci Sequence as a numpy array"""
n = int(fabs(n)) if n >= 0 else 2
n -= 1
a, b = 1, 1
result = np.array([a])
for _ in range(n):
a, b = b, a + b
result = np.append(result, a)
fib_sum = np.sum(result)
if fib_sum > 0:
return result / fib_sum
else:
return result

View File

@@ -4,23 +4,23 @@ import numpy as np
import talib
from jesse.helpers import get_candle_source, np_shift
from jesse.helpers import slice_candles
GATOR = namedtuple('GATOR', ['upper', 'lower', 'upper_change', 'lower_change'])
def gatorosc(candles: np.ndarray, source_type="close", sequential=False) -> GATOR:
def gatorosc(candles: np.ndarray, source_type: str = "close", sequential: bool = False) -> GATOR:
"""
Gator Oscillator by Bill M. Williams
:param candles: np.ndarray
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: GATOR(upper, lower, upper_change, lower_change)
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
@@ -39,6 +39,7 @@ def gatorosc(candles: np.ndarray, source_type="close", sequential=False) -> GATO
else:
return GATOR(upper[-1], lower[-1], upper_change[-1], lower_change[-1])
def numpy_ewma(data, window):
"""
@@ -47,13 +48,11 @@ def numpy_ewma(data, window):
:return:
"""
alpha = 1 / window
scale = 1 / (1 - alpha)
# scale = 1 / (1 - alpha)
n = data.shape[0]
scale_arr = (1 - alpha) ** (-1 * np.arange(n))
weights = (1 - alpha) ** np.arange(n)
pw0 = (1 - alpha) ** (n - 1)
mult = data * pw0 * scale_arr
cumsums = mult.cumsum()
out = cumsums * scale_arr[::-1] / weights.cumsum()
return out
return cumsums * scale_arr[::-1] / weights.cumsum()

View File

@@ -1,36 +1,54 @@
import math
from typing import Union
import numpy as np
try:
from numba import njit
except ImportError:
njit = lambda a : a
from jesse.helpers import get_candle_source
from jesse.helpers import get_candle_source, slice_candles
def gauss(candles: np.ndarray, period=14, poles=4, source_type="close", sequential=False) -> Union[float, np.ndarray]:
def gauss(candles: np.ndarray, period: int = 14, poles: int = 4, source_type: str = "close",
sequential: bool = False) -> Union[float, np.ndarray]:
"""
Gaussian Filter
:param candles: np.ndarray
:param period: int - default=14
:param poles: int - default=4
:param period: int - default: 14
:param poles: int - default: 4
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
if len(candles.shape) == 1:
source = candles
else:
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
source = get_candle_source(candles, source_type=source_type)
N = len(source)
fil, to_fill = gauss_fast(source, period, poles)
if to_fill != 0:
res = np.insert(fil[poles:], 0, np.repeat(np.nan, to_fill))
else:
res = fil[poles:]
return res if sequential else res[-1]
@njit
def gauss_fast(source, period, poles):
N = source.size
source = source[~np.isnan(source)]
to_fill = N - len(source)
PI = math.pi
beta = (1 - math.cos(2 * PI / period)) / (math.pow(2, 1 / poles) - 1)
alpha = -beta + math.sqrt(math.pow(beta, 2) + 2 * beta)
to_fill = N - source.size
PI = np.pi
beta = (1 - np.cos(2 * PI / period)) / (np.power(2, 1 / poles) - 1)
alpha = -beta + np.sqrt(np.power(beta, 2) + 2 * beta)
fil = np.zeros(poles + len(source))
fil = np.zeros(poles + source.size)
if poles == 1:
coeff = np.array([alpha, (1 - alpha)])
elif poles == 2:
@@ -40,7 +58,7 @@ def gauss(candles: np.ndarray, period=14, poles=4, source_type="close", sequenti
elif poles == 4:
coeff = np.array([alpha ** 4, 4 * (1 - alpha), -6 * (1 - alpha) ** 2, 4 * (1 - alpha) ** 3, -(1 - alpha) ** 4])
for i in range(len(source)):
for i in range(source.size):
if poles == 1:
val = np.array([source[i].item(), fil[i]])
elif poles == 2:
@@ -52,12 +70,4 @@ def gauss(candles: np.ndarray, period=14, poles=4, source_type="close", sequenti
fil[poles + i] = np.dot(coeff, val)
if to_fill != 0:
res = np.insert(fil[poles:], 0, np.repeat(np.nan, to_fill))
else:
res = fil[poles:]
if sequential:
return res
else:
return None if np.isnan(res[-1]) else res[-1]
return fil, to_fill

View File

@@ -1,37 +1,47 @@
import math
from typing import Union
import numpy as np
from jesse.helpers import get_candle_source
try:
from numba import njit
except ImportError:
njit = lambda a : a
from jesse.helpers import get_candle_source, slice_candles
def high_pass(candles: np.ndarray, period=48, source_type="close", sequential=False) -> Union[float, np.ndarray]:
def high_pass(candles: np.ndarray, period: int = 48, source_type: str = "close", sequential: bool = False) -> Union[
float, np.ndarray]:
"""
High Pass Filter indicator by John F. Ehlers
(1 pole) high-pass filter indicator by John F. Ehlers
:param candles: np.ndarray
:param period: int - default=48
:param period: int - default: 48
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
if len(candles.shape) == 1:
source = candles
else:
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
source = get_candle_source(candles, source_type=source_type)
hpf = np.full_like(source, 0)
for i in range(source.shape[0]):
if not (i < 2):
alpha_arg = 2 * math.pi / (period * 1.414)
alpha1 = (math.cos(alpha_arg) + math.sin(alpha_arg) - 1) / math.cos(alpha_arg)
hpf[i] = math.pow(1.0 - alpha1 / 2.0, 2) * (source[i] - 2 * source[i - 1] + source[i - 2]) + 2 * (1 - alpha1) * hpf[i - 1] - math.pow(1 - alpha1, 2) * hpf[i - 2]
hpf = high_pass_fast(source, period)
if sequential:
return hpf
else:
return None if np.isnan(hpf[-1]) else hpf[-1]
@njit
def high_pass_fast(source, period): # Function is compiled to machine code when called the first time
k = 1
alpha = 1 + (np.sin(2 * np.pi * k / period) - 1) / np.cos(2 * np.pi * k / period)
newseries = np.copy(source)
for i in range(1, source.shape[0]):
newseries[i] = (1 - alpha / 2) * source[i] - (1 - alpha / 2) * source[i - 1] \
+ (1 - alpha) * newseries[i - 1]
return newseries

View File

@@ -0,0 +1,49 @@
from typing import Union
import numpy as np
try:
from numba import njit
except ImportError:
njit = lambda a : a
from jesse.helpers import get_candle_source, slice_candles
def high_pass_2_pole(candles: np.ndarray, period: int = 48, source_type: str = "close", sequential: bool = False) -> \
Union[
float, np.ndarray]:
"""
(2 pole) high-pass filter indicator by John F. Ehlers
:param candles: np.ndarray
:param period: int - default: 48
:param source_type: str - default: "close"
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if len(candles.shape) == 1:
source = candles
else:
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
hpf = high_pass_2_pole_fast(source, period)
if sequential:
return hpf
else:
return None if np.isnan(hpf[-1]) else hpf[-1]
@njit
def high_pass_2_pole_fast(source, period, K=0.707): # Function is compiled to machine code when called the first time
alpha = 1 + (np.sin(2 * np.pi * K / period) - 1) / np.cos(2 * np.pi * K / period)
newseries = np.copy(source)
for i in range(2, source.shape[0]):
newseries[i] = (1 - alpha / 2) ** 2 * source[i] \
- 2 * (1 - alpha / 2) ** 2 * source[i - 1] \
+ (1 - alpha / 2) ** 2 * source[i - 2] \
+ 2 * (1 - alpha) * newseries[i - 1] - (1 - alpha) ** 2 * newseries[i - 2]
return newseries

View File

@@ -3,24 +3,28 @@ from typing import Union
import numpy as np
import tulipy as ti
from jesse.helpers import get_candle_source
from jesse.helpers import get_candle_source, same_length, slice_candles
def hma(candles: np.ndarray, period=5, source_type="close", sequential=False) -> Union[float, np.ndarray]:
def hma(candles: np.ndarray, period: int = 5, source_type: str = "close", sequential: bool = False) -> Union[
float, np.ndarray]:
"""
Hull Moving Average
:param candles: np.ndarray
:param period: int - default: 5
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
# Accept normal array too.
if len(candles.shape) == 1:
source = candles
else:
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
source = get_candle_source(candles, source_type=source_type)
res = ti.hma(np.ascontiguousarray(source), period=period)
return np.concatenate((np.full((candles.shape[0] - res.shape[0]), np.nan), res), axis=0) if sequential else res[-1]
return same_length(candles, res) if sequential else res[-1]

View File

@@ -4,20 +4,20 @@ import numpy as np
import talib
from jesse.helpers import get_candle_source
from jesse.helpers import slice_candles
def ht_dcperiod(candles: np.ndarray, source_type="close", sequential=False) -> Union[float, np.ndarray]:
def ht_dcperiod(candles: np.ndarray, source_type: str = "close", sequential: bool = False) -> Union[float, np.ndarray]:
"""
HT_DCPERIOD - Hilbert Transform - Dominant Cycle Period
:param candles: np.ndarray
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
res = talib.HT_DCPERIOD(source)

View File

@@ -4,22 +4,22 @@ import numpy as np
import talib
from jesse.helpers import get_candle_source
from jesse.helpers import slice_candles
def ht_dcphase(candles: np.ndarray, source_type="close", sequential=False) -> Union[float, np.ndarray]:
def ht_dcphase(candles: np.ndarray, source_type: str = "close", sequential: bool = False) -> Union[float, np.ndarray]:
"""
HT_DCPHASE - Hilbert Transform - Dominant Cycle Phase
:param candles: np.ndarray
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
res = talib.HT_DCPHASE (source)
res = talib.HT_DCPHASE(source)
return res if sequential else res[-1]

View File

@@ -4,21 +4,22 @@ import numpy as np
import talib
from jesse.helpers import get_candle_source
from jesse.helpers import slice_candles
IQ = namedtuple('IQ', ['inphase', 'quadrature'])
def ht_phasor(candles: np.ndarray, source_type="close", sequential=False) -> IQ:
def ht_phasor(candles: np.ndarray, source_type: str = "close", sequential: bool = False) -> IQ:
"""
HT_PHASOR - Hilbert Transform - Phasor Components
:param candles: np.ndarray
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: IQ(inphase, quadrature)
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
inphase, quadrature = talib.HT_PHASOR(source)

View File

@@ -4,21 +4,22 @@ import numpy as np
import talib
from jesse.helpers import get_candle_source
from jesse.helpers import slice_candles
SINEWAVE = namedtuple('SINEWAVE', ['sine', 'lead'])
def ht_sine(candles: np.ndarray, source_type="close", sequential=False) -> SINEWAVE:
def ht_sine(candles: np.ndarray, source_type: str = "close", sequential: bool = False) -> SINEWAVE:
"""
HT_SINE - Hilbert Transform - SineWave
:param candles: np.ndarray
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: SINEWAVE(sine, lead)
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
sine, leadsine = talib.HT_SINE(source)

View File

@@ -4,22 +4,25 @@ import numpy as np
import talib
from jesse.helpers import get_candle_source
from jesse.helpers import slice_candles
def ht_trendline(candles: np.ndarray, source_type="close", sequential=False) -> Union[float, np.ndarray]:
def ht_trendline(candles: np.ndarray, source_type: str = "close", sequential: bool = False) -> Union[float, np.ndarray]:
"""
HT_TRENDLINE - Hilbert Transform - Instantaneous Trendline
:param candles: np.ndarray
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
if len(candles.shape) == 1:
source = candles
else:
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
source = get_candle_source(candles, source_type=source_type)
res = talib.HT_TRENDLINE(source)
return res if sequential else res[-1]

View File

@@ -4,20 +4,20 @@ import numpy as np
import talib
from jesse.helpers import get_candle_source
from jesse.helpers import slice_candles
def ht_trendmode(candles: np.ndarray, source_type="close", sequential=False) -> Union[float, np.ndarray]:
def ht_trendmode(candles: np.ndarray, source_type: str = "close", sequential: bool = False) -> Union[float, np.ndarray]:
"""
HT_TRENDMODE - Hilbert Transform - Trend vs Cycle Mode
:param candles: np.ndarray
:param source_type: str - default: "close"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: int | np.ndarray
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
res = talib.HT_TRENDMODE(source)

View File

@@ -0,0 +1,209 @@
import numpy as np
try:
from numba import njit
except ImportError:
njit = lambda a : a
from jesse.helpers import get_candle_source, slice_candles
from scipy import signal
def hurst_exponent(candles: np.ndarray, min_chunksize: int = 8, max_chunksize: int = 200, num_chunksize:int=5, method:int=1, source_type: str = "close") -> float:
"""
Hurst Exponent
:param candles: np.ndarray
:param min_chunksize: int - default: 8
:param max_chunksize: int - default: 200
:param num_chunksize: int - default: 5
:param method: int - default: 1 - 0: RS | 1: DMA | 2: DSOD
:param source_type: str - default: "close"
:return: float
"""
if len(candles.shape) == 1:
source = candles
else:
candles = slice_candles(candles, False)
source = get_candle_source(candles, source_type=source_type)
if method == 0:
h = hurst_rs(np.diff(source), min_chunksize, max_chunksize, num_chunksize)
elif method == 1:
h = hurst_dma(source, min_chunksize, max_chunksize, num_chunksize)
elif method == 2:
h = hurst_dsod(source)
else:
raise NotImplementedError('The method choose is not implemented.')
return None if np.isnan(h) else h
@njit
def hurst_rs(x, min_chunksize, max_chunksize, num_chunksize):
"""Estimate the Hurst exponent using R/S method.
Estimates the Hurst (H) exponent using the R/S method from the time series.
The R/S method consists of dividing the series into pieces of equal size
`series_len` and calculating the rescaled range. This repeats the process
for several `series_len` values and adjusts data regression to obtain the H.
`series_len` will take values between `min_chunksize` and `max_chunksize`,
the step size from `min_chunksize` to `max_chunksize` can be controlled
through the parameter `step_chunksize`.
Parameters
----------
x : 1D-array
A time series to calculate hurst exponent, must have more elements
than `min_chunksize` and `max_chunksize`.
min_chunksize : int
This parameter allow you control the minimum window size.
max_chunksize : int
This parameter allow you control the maximum window size.
num_chunksize : int
This parameter allow you control the size of the step from minimum to
maximum window size. Bigger step means fewer calculations.
out : 1-element-array, optional
one element array to store the output.
Returns
-------
H : float
A estimation of Hurst exponent.
References
----------
Hurst, H. E. (1951). Long term storage capacity of reservoirs. ASCE
Transactions, 116(776), 770-808.
Alessio, E., Carbone, A., Castelli, G. et al. Eur. Phys. J. B (2002) 27:
197. http://dx.doi.org/10.1140/epjb/e20020150
"""
N = len(x)
max_chunksize += 1
rs_tmp = np.empty(N, dtype=np.float64)
chunk_size_list = np.linspace(min_chunksize, max_chunksize, num_chunksize) \
.astype(np.int64)
rs_values_list = np.empty(num_chunksize, dtype=np.float64)
# 1. The series is divided into chunks of chunk_size_list size
for i in range(num_chunksize):
chunk_size = chunk_size_list[i]
# 2. it iterates on the indices of the first observation of each chunk
number_of_chunks = int(len(x) / chunk_size)
for idx in range(number_of_chunks):
# next means no overlapping
# convert index to index selection of each chunk
ini = idx * chunk_size
end = ini + chunk_size
chunk = x[ini:end]
# 2.1 Calculate the RS (chunk_size)
z = np.cumsum(chunk - np.mean(chunk))
rs_tmp[idx] = np.divide(
np.max(z) - np.min(z), # range
np.nanstd(chunk) # standar deviation
)
# 3. Average of RS(chunk_size)
rs_values_list[i] = np.nanmean(rs_tmp[:idx + 1])
# 4. calculate the Hurst exponent.
H, c = np.linalg.lstsq(
a=np.vstack((np.log(chunk_size_list), np.ones(num_chunksize))).T,
b=np.log(rs_values_list)
)[0]
return H
def hurst_dma(prices, min_chunksize=8, max_chunksize=200, num_chunksize=5):
"""Estimate the Hurst exponent using R/S method.
Estimates the Hurst (H) exponent using the DMA method from the time series.
The DMA method consists on calculate the moving average of size `series_len`
and subtract it to the original series and calculating the standard
deviation of that result. This repeats the process for several `series_len`
values and adjusts data regression to obtain the H. `series_len` will take
values between `min_chunksize` and `max_chunksize`, the step size from
`min_chunksize` to `max_chunksize` can be controlled through the parameter
`step_chunksize`.
Parameters
----------
prices
min_chunksize
max_chunksize
num_chunksize
Returns
-------
hurst_exponent : float
Estimation of hurst exponent.
References
----------
Alessio, E., Carbone, A., Castelli, G. et al. Eur. Phys. J. B (2002) 27:
197. https://dx.doi.org/10.1140/epjb/e20020150
"""
max_chunksize += 1
N = len(prices)
n_list = np.arange(min_chunksize, max_chunksize, num_chunksize, dtype=np.int64)
dma_list = np.empty(len(n_list))
factor = 1 / (N - max_chunksize)
# sweeping n_list
for i, n in enumerate(n_list):
b = np.divide([n - 1] + (n - 1) * [-1], n) # do the same as: y - y_ma_n
noise = np.power(signal.lfilter(b, 1, prices)[max_chunksize:], 2)
dma_list[i] = np.sqrt(factor * np.sum(noise))
H, const = np.linalg.lstsq(
a=np.vstack([np.log10(n_list), np.ones(len(n_list))]).T,
b=np.log10(dma_list), rcond=None
)[0]
return H
def hurst_dsod(x):
"""Estimate Hurst exponent on data timeseries.
The estimation is based on the discrete second order derivative. Consists on
get two different noise of the original series and calculate the standard
deviation and calculate the slope of two point with that values.
source: https://gist.github.com/wmvanvliet/d883c3fe1402c7ced6fc
Parameters
----------
x : numpy array
time series to estimate the Hurst exponent for.
Returns
-------
h : float
The estimation of the Hurst exponent for the given time series.
References
----------
Istas, J.; G. Lang (1994), “Quadratic variations and estimation of the local
Hölder index of data Gaussian process,” Ann. Inst. Poincaré, 33, pp. 407436.
Notes
-----
This hurst_ets is data literal traduction of wfbmesti.m of waveleet toolbox
from matlab.
"""
y = np.cumsum(np.diff(x, axis=0), axis=0)
# second order derivative
b1 = [1, -2, 1]
y1 = signal.lfilter(b1, 1, y, axis=0)
y1 = y1[len(b1) - 1:] # first values contain filter artifacts
# wider second order derivative
b2 = [1, 0, -2, 0, 1]
y2 = signal.lfilter(b2, 1, y, axis=0)
y2 = y2[len(b2) - 1:] # first values contain filter artifacts
s1 = np.mean(y1 ** 2, axis=0)
s2 = np.mean(y2 ** 2, axis=0)
return 0.5 * np.log2(s2 / s1)

54
jesse/indicators/hwma.py Normal file
View File

@@ -0,0 +1,54 @@
from typing import Union
import numpy as np
try:
from numba import njit
except ImportError:
njit = lambda a : a
from jesse.helpers import get_candle_source, slice_candles, same_length
def hwma(candles: np.ndarray, na: float = 0.2, nb: float = 0.1, nc: float = 0.1, source_type: str = "close", sequential: bool = False) -> Union[
float, np.ndarray]:
"""
Holt-Winter Moving Average
:param candles: np.ndarray
:param na: float - default: 0.2
:param nb: float - default: 0.1
:param nc: float - default: 0.1
:param source_type: str - default: "close"
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if not ((0 < na < 1) or (0 < nb < 1) or (0 < nc < 1)):
raise ValueError("Bad parameters. They have to be: 0 < na nb nc < 1")
# Accept normal array too.
if len(candles.shape) == 1:
source = candles
else:
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
source_without_nan = source[~np.isnan(source)]
res = hwma_fast(source_without_nan, na, nb, nc)
res = same_length(candles, res)
return res if sequential else res[-1]
@njit
def hwma_fast(source, na, nb, nc):
last_a = last_v = 0
last_f = source[0]
newseries = np.copy(source)
for i in range(source.size):
F = (1.0 - na) * (last_f + last_v + 0.5 * last_a) + na * source[i]
V = (1.0 - nb) * (last_v + last_a) + nb * (F - last_f)
A = (1.0 - nc) * last_a + nc * (V - last_v)
newseries[i] = F + V + 0.5 * A
last_a, last_f, last_v = A, F, V # update values
return newseries

View File

@@ -5,23 +5,23 @@ import numpy as np
IchimokuCloud = namedtuple('IchimokuCloud', ['conversion_line', 'base_line', 'span_a', 'span_b'])
def ichimoku_cloud(candles: np.ndarray, conversion_line_period=9, base_line_period=26, lagging_line_period=52,
displacement=26) -> IchimokuCloud:
def ichimoku_cloud(candles: np.ndarray, conversion_line_period: int = 9, base_line_period: int = 26,
lagging_line_period: int = 52, displacement: int = 26) -> IchimokuCloud:
"""
Ichimoku Cloud
:param candles: np.ndarray
:param conversion_line_period: int - default=9
:param base_line_period: int - default=26
:param lagging_line_period: int - default=52
:param displacement: - default=26
:param conversion_line_period: int - default: 9
:param base_line_period: int - default: 26
:param lagging_line_period: int - default: 52
:param displacement: - default: 26
:return: IchimokuCloud(conversion_line, base_line, span_a, span_b)
"""
if len(candles) < 80:
if candles.shape[0] < 80:
return IchimokuCloud(np.nan, np.nan, np.nan, np.nan)
if len(candles) > 80:
if candles.shape[0] > 80:
candles = candles[-80:]
# earlier

View File

@@ -4,48 +4,40 @@ import numpy as np
import talib
from jesse.helpers import np_shift
from jesse.helpers import slice_candles
IchimokuCloud = namedtuple('IchimokuCloud',
['conversion_line', 'base_line', 'span_a', 'span_b', 'lagging_line', 'future_span_a',
'future_span_b'])
def ichimoku_cloud_seq(candles: np.ndarray, conversion_line_period=9, base_line_period=26, lagging_line_period=52,
displacement=26, sequential=False) -> IchimokuCloud:
def ichimoku_cloud_seq(candles: np.ndarray, conversion_line_period: int = 9, base_line_period: int = 26,
lagging_line_period: int = 52, displacement: int = 26,
sequential: bool = False) -> IchimokuCloud:
"""
Ichimoku Cloud
:param candles: np.ndarray
:param conversion_line_period: int - default=9
:param base_line_period: int - default=26
:param lagging_line_period: int - default=52
:param displacement: - default=26
:param sequential: bool - default=False
:param conversion_line_period: int - default: 9
:param base_line_period: int - default: 26
:param lagging_line_period: int - default: 52
:param displacement: - default: 26
:param sequential: bool - default: False
:return: IchimokuCloud
"""
if len(candles) < lagging_line_period + displacement:
if candles.shape[0] < lagging_line_period + displacement:
raise ValueError("Too few candles available for lagging_line_period + displacement.")
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
small_ph = talib.MAX(candles[:, 3], conversion_line_period)
small_pl = talib.MIN(candles[:, 4], conversion_line_period)
conversion_line = (small_ph + small_pl) / 2
mid_ph = talib.MAX(candles[:, 3], base_line_period)
mid_pl = talib.MIN(candles[:, 4], base_line_period)
base_line = (mid_ph + mid_pl) / 2
long_ph = talib.MAX(candles[:, 3], lagging_line_period)
long_pl = talib.MIN(candles[:, 4], lagging_line_period)
span_b_pre = (long_ph + long_pl) / 2
conversion_line = _line_helper(candles, conversion_line_period)
base_line = _line_helper(candles, base_line_period)
span_b_pre = _line_helper(candles, lagging_line_period)
span_b = np_shift(span_b_pre, displacement, fill_value=np.nan)
span_a_pre = (conversion_line + base_line) / 2
span_a = np_shift(span_a_pre, displacement, fill_value=np.nan)
lagging_line = np_shift(candles[:, 2], displacement - 1, fill_value=np.nan)
if sequential:
@@ -53,3 +45,8 @@ def ichimoku_cloud_seq(candles: np.ndarray, conversion_line_period=9, base_line_
else:
return IchimokuCloud(conversion_line[-1], base_line[-1], span_a[-1], span_b[-1], lagging_line[-1],
span_a_pre[-1], span_b_pre[-1])
def _line_helper(candles, period):
small_ph = talib.MAX(candles[:, 3], period)
small_pl = talib.MIN(candles[:, 4], period)
return (small_ph + small_pl) / 2

View File

@@ -0,0 +1,36 @@
from typing import Union
import talib
import numpy as np
from jesse.helpers import get_candle_source, slice_candles, same_length
def ift_rsi(candles: np.ndarray, rsi_period: int = 5, wma_period: int =9, source_type: str = "close", sequential: bool = False) -> Union[
float, np.ndarray]:
"""
Modified Inverse Fisher Transform applied on RSI
:param candles: np.ndarray
:param rsi_period: int - default: 5
:param wma_period: int - default: 9
:param source_type: str - default: "close"
:param sequential: bool - default: False
:return: float | np.ndarray
"""
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
v1 = 0.1 * (talib.RSI(source, rsi_period) - 50)
v2 = talib.WMA(v1, wma_period)
res = (((2*v2) ** 2 - 1) / ((2*v2) ** 2 + 1))
return same_length(candles, res) if sequential else res[-1]

View File

@@ -1,45 +1,53 @@
from collections import namedtuple
import numpy as np
try:
from numba import njit
except ImportError:
njit = lambda a : a
from jesse.helpers import get_candle_source
from jesse.helpers import get_candle_source, slice_candles
ITREND = namedtuple('ITREND', ['signal', 'it', 'trigger'])
def itrend(candles: np.ndarray, alpha=0.07, source_type="hl2", sequential=False) -> ITREND:
def itrend(candles: np.ndarray, alpha: float = 0.07, source_type: str = "hl2", sequential: bool = False) -> ITREND:
"""
Instantaneous Trendline
:param candles: np.ndarray
:param alpha: float - default: 0.07
:param source_type: str - default: "hl2"
:param sequential: bool - default=False
:param sequential: bool - default: False
:return: ITREND(signal, it, trigger)
"""
if not sequential and len(candles) > 240:
candles = candles[-240:]
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
coeff = np.array(
[(alpha - alpha ** 2 / 4), alpha ** 2 / 2, - (alpha - alpha ** 2 * 3 / 4), 2 * (1 - alpha), - (1 - alpha) ** 2])
signal, it, trigger = itrend_fast(source, alpha)
if sequential:
return ITREND(signal, it, trigger)
else:
return ITREND(signal[-1], it[-1], trigger[-1])
@njit
def itrend_fast(source, alpha):
it = np.copy(source)
for i in range(2, 7):
it[i] = (source[i] + 2 * source[i - 1] + source[i - 2]) / 4
for i in range(7, source.shape[0]):
val = np.array([source[i], source[i - 1], source[i - 2], it[i - 1], it[i - 2]])
it[i] = np.matmul(coeff, val)
it[i] = (alpha - alpha ** 2 / 4) * source[i] \
+ alpha ** 2 / 2 * source[i - 1] \
- (alpha - alpha ** 2 * 3 / 4) * source[i - 2] \
+ 2 * (1 - alpha) * it[i - 1] - (1 - alpha) ** 2 * it[i - 2]
# compute lead 2 trigger & signal
lag2 = np.roll(it, 20)
lag2[:20] = it[:20]
trigger = 2 * it - lag2
signal = (trigger > it) * 1 - (trigger < it) * 1
if sequential:
return ITREND(signal, it, trigger)
else:
return ITREND(signal[-1], it[-1], trigger[-1])
return signal, it, trigger

48
jesse/indicators/jma.py Normal file
View File

@@ -0,0 +1,48 @@
from typing import Union
import numpy as np
try:
from numba import njit
except ImportError:
njit = lambda a : a
from jesse.helpers import get_candle_source, slice_candles
def jma(candles: np.ndarray, period:int=7, phase:float=50, power:int=2, source_type:str='close', sequential:bool=False) -> Union[
float, np.ndarray]:
"""
Jurik Moving Average
Port of: https://tradingview.com/script/nZuBWW9j-Jurik-Moving-Average/
"""
if len(candles.shape) == 1:
source = candles
else:
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
phaseRatio = 0.5 if phase < -100 else (2.5 if phase > 100 else phase / 100 + 1.5)
beta = 0.45 * (period - 1) / (0.45 * (period - 1) + 2)
alpha = pow(beta, power)
res = jma_helper(source, phaseRatio, beta, alpha)
return res if sequential else res[-1]
@njit
def jma_helper(src, phaseRatio, beta, alpha):
jma_val = np.copy(src)
e0 = np.full_like(src, 0)
e1 = np.full_like(src, 0)
e2 = np.full_like(src, 0)
for i in range(1, src.shape[0]):
e0[i] = (1 - alpha) * src[i] + alpha * e0[i-1]
e1[i] = (src[i] - e0[i]) * (1 - beta) + beta * e1[i-1]
e2[i] = (e0[i] + phaseRatio * e1[i] - jma_val[i - 1]) * pow(1 - alpha, 2) + pow(alpha, 2) * e2[i - 1]
jma_val[i] = e2[i] + jma_val[i - 1]
return jma_val

28
jesse/indicators/jsa.py Normal file
View File

@@ -0,0 +1,28 @@
from typing import Union
import numpy as np
from jesse.helpers import get_candle_source, slice_candles, np_shift
def jsa(candles: np.ndarray, period: int = 30, source_type: str = "close", sequential: bool = False) -> Union[
float, np.ndarray]:
"""
Jsa Moving Average
:param candles: np.ndarray
:param period: int - default: 30
:param source_type: str - default: "close"
:param sequential: bool - default: False
:return: float | np.ndarray
"""
if len(candles.shape) == 1:
source = candles
else:
candles = slice_candles(candles, sequential)
source = get_candle_source(candles, source_type=source_type)
res = (source + np_shift(source, period, np.nan)) / 2
return res if sequential else res[-1]

Some files were not shown because too many files have changed in this diff Show More