# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['minitrade',
 'minitrade.admin',
 'minitrade.admin.pages',
 'minitrade.backtest',
 'minitrade.backtest.core',
 'minitrade.backtest.core.test',
 'minitrade.broker',
 'minitrade.datasource',
 'minitrade.trader',
 'minitrade.utils']

package_data = \
{'': ['*']}

install_requires = \
['apscheduler>=3.9.1.post1,<4.0.0',
 'bokeh>=2.4.3,<3.0.0',
 'click>=8.1.3,<9.0.0',
 'fastapi[all]>=0.92.0,<0.93.0',
 'mailjet-rest>=1.3.4,<2.0.0',
 'matplotlib>=3.6.2,<4.0.0',
 'minitrade-scikit-optimize>=0.9.1,<0.10.0',
 'nanoid>=2.0.0,<3.0.0',
 'numpy>=1.23.5,<2.0.0',
 'pandas-ta>=0.3.14b0,<0.4.0',
 'pandas>=1.5.2,<2.0.0',
 'psutil>=5.9.4,<6.0.0',
 'pydantic>=1.10.2,<2.0.0',
 'pypika>=0.48.9,<0.49.0',
 'pyyaml>=6.0,<7.0',
 'requests>=2.28.1,<3.0.0',
 'scikit-learn>=1.2.1,<2.0.0',
 'scipy>=1.10.1,<2.0.0',
 'seaborn>=0.12.1,<0.13.0',
 'selenium>=4.7.2,<5.0.0',
 'streamlit>=1.15.2,<2.0.0',
 'tqdm>=4.64.1,<5.0.0',
 'watchdog>=2.2.0,<3.0.0',
 'yfinance>=0.1.93,<0.2.0']

entry_points = \
{'console_scripts': ['minitrade = minitrade.cli:mtcli']}

setup_kwargs = {
    'name': 'minitrade',
    'version': '0.1.1',
    'description': 'A personal automated trading system',
    'long_description': "## Minitrade\n\n**[Documentation](https://dodid.github.io/minitrade/)**\n\n- [Minitrade](#minitrade)\n- [Installation](#installation)\n- [Backtesting](#backtesting)\n  - [Single asset strattegy](#single-asset-strattegy)\n  - [Multi-asset strategy](#multi-asset-strategy)\n- [Trading](#trading)\n  - [Launch](#launch)\n  - [Configure](#configure)\n  - [IB gateway](#ib-gateway)\n\n\n**Minitrade** is a personal trading system that supports both strategy backtesting and automated order execution.\n\nIt integrates with [Backtesting.py](https://github.com/kernc/backtesting.py) under the hood, and:\n- Is fully compatible with Backtesting.py strategies with minor adaptions.\n- Supports multi-asset portfolio and rebalancing strategies.\n\nOr it can be used as a full trading system that:\n- Automatically executes trading strategies and submits orders.\n- Manages strategy execution via web console.\n- Runs on very low cost machines. \n\nLimitations as a backtesting framework:\n- Multi-asset strategy only supports long positions and market order. \n\nLimitations (for now) as a trading system:\n- Tested only on Linux\n- Support only daily bar and market-on-open order\n- Support only long positions\n- Support only Interactive Brokers\n\nOn the other hand, Minitrade is intended to be easily hackable to fit individual's needs.\n\n## Installation\n\nMinitrade requires `python=3.10.*`\n\n\nIf only used as a backtesting framework:\n\n    $ pip install minitrade\n\nIf used as a trading system, continue with the following:\n\n    $ minitrade init\n\nFor a detailed setup guide on Ubuntu, check out [Installation](INSTALL.md).\n\n## Backtesting\n\nMinitrade uses [Backtesting.py](https://github.com/kernc/backtesting.py) as the core library for backtesting and adds the capability to implement multi-asset strategies. \n\n### Single asset strattegy\n\nFor single asset strategies, those written for Backtesting.py can be easily adapted to work with Minitrade. The following illustrates what changes are necessary:\n\n```python\nfrom minitrade.backtest import Backtest, Strategy\nfrom minitrade.backtest.core.lib import crossover\n\nfrom minitrade.backtest.core.test import SMA, GOOG\n\n\nclass SmaCross(Strategy):\n    def init(self):\n        price = self.data.Close\n        self.ma1 = self.I(SMA, price, 10, overlay=True)\n        self.ma2 = self.I(SMA, price, 20, overlay=True)\n\n    def next(self):\n        if crossover(self.ma1, self.ma2):\n            self.position().close()\n            self.buy()\n        elif crossover(self.ma2, self.ma1):\n            self.position().close()\n            self.sell()\n\n\nbt = Backtest(GOOG, SmaCross, commission=.002)\nstats = bt.run()\nbt.plot()\n```\n\n1. Change to import from minitrade modules. Generally `backtesting` becomes `minitrade.backtest.core`.\n2. Minitrade expects `Volume` data to be always avaiable. `Strategy.data` should be consisted of OHLCV.\n3. Minitrade doesn't try to guess where to plot the indicators. So if you want to overlay the indicators on the main chart, set `overlay=True` explicitly.\n4. `Strategy.position` is no longer a property but a function. Any occurrence of `self.position` should be changed to `self.position()`. \n\nThat's it. \n\n![plot of single-asset strategy](https://imgur.com/N3E2d6m.jpg)\n\nAlso note that some original utility functions and strategy classes only make sense for single asset strategy. Don't use those in multi-asset strategies.\n\n### Multi-asset strategy\n\nMinitrade extends `Backtesting.py` to support backtesting of multi-asset strategies. \n\nMulti-asset strategies take a 2-level DataFrame as data input. For example, for a strategy class that intends to invest in AAPL and GOOG as a portfolio, the `self.data` should look like:\n\n```\n$ print(self.data)\n\n                          AAPL                              GOOG \n                          Open  High  Low   Close Volume    Open  High  Low   Close Volume\nDate          \n2018-01-02 00:00:00-05:00 40.39 40.90 40.18 40.89 102223600 52.42 53.35 52.26 53.25 24752000\n2018-01-03 00:00:00-05:00 40.95 41.43 40.82 40.88 118071600 53.22 54.31 53.16 54.12 28604000\n2018-01-04 00:00:00-05:00 40.95 41.18 40.85 41.07 89738400 54.40 54.68 54.20 54.32 20092000\n2018-01-05 00:00:00-05:00 41.17 41.63 41.08 41.54 94640000 54.70 55.21 54.60 55.11 25582000\n2018-01-08 00:00:00-05:00 41.38 41.68 41.28 41.38 82271200 55.11 55.56 55.08 55.35 20952000\n```\n\nLike in `Backtesting.py`, `self.data` is `_Data` type that supports progressively revealing of data, and the raw DataFrame can be accessed by `self.data.df`. \n\nTo facilitate indicator calculation, Minitrade has built-in integration with [pandas_ta](https://github.com/twopirllc/pandas-ta) a TA library. `pandas_ta` is accessible using `.ta` property of any DataFrame. Check out [here](https://github.com/twopirllc/pandas-ta#pandas-ta-dataframe-extension) for usage. `.ta` is also enhanced to support 2-level DataFrames. \n\nFor example,\n\n```\n$ print(self.data.df.ta.sma(3))\n\n                                 AAPL       GOOG\nDate                                            \n2018-01-02 00:00:00-05:00         NaN        NaN\n2018-01-03 00:00:00-05:00         NaN        NaN\n2018-01-04 00:00:00-05:00   40.946616  53.898000\n2018-01-05 00:00:00-05:00   41.163408  54.518500\n2018-01-08 00:00:00-05:00   41.331144  54.926167\n```\n\nEven simpler, `self.data.ta.sma(3)` works the same on `self.data`.\n\n\n`self.I()` can take both DataFrame/Series and functions as arguments to define an indicator. If DataFrame/Series is given as input, it's expected to have exactly the same index as `self.data`. For example,\n\n```\nself.sma = self.I(self.data.df.ta.sma(3), name='SMA_3')\n```\n\nWithin `Strategy.next()`, indicators are returned as type `_Array`, essentially `numpy.ndarray`, same as in `Backtesting.py`. The `.df` accessor returns either `DataFrame` or `Series` of the corresponding value. It's the caller's responsibility to know which exact type should be returned. `.s` accessor is also available but only as a syntax suger to return a `Series`. If the actual data is a DataFrame, `.s` throws a `ValueError`. \n\nA key addition to support multi-asset strategy is a `Strategy.alloc` attribute, which combined with `Strategy.rebalance()` API, allows to specify how cash value should be allocate among the different assets. \n\nHere is an example:\n\n```python\n# This strategy evenly allocates cash into the assets\n# that have the top 2 highest rate-of-change every day, \n# on condition that the ROC is possitive.\n\nclass TopPositiveRoc(Strategy):\n    n = 10\n\n    def init(self):\n        roc = self.data.ta.roc(self.n)\n        self.roc = self.I(roc, name='ROC')\n\n    def next(self):\n        roc = self.roc.df.iloc[-1]\n        self.alloc.add(\n            roc.nlargest(2).index, \n            roc > 0\n        ).equal_weight()\n        self.rebalance()\n```\n\n`self.alloc` keeps track of what assets you want to buy and how much weight you want to assign to each. \n\nAt the beginning of each `Strategy.next()` call, `self.alloc` starts empty. \n\nUse `alloc.add()` to add assets to a candidate pool. `alloc.add()` takes either an index or a boolean Series as input. If it's an index, all asset in the index are added to the pool. If it's a boolean Series, index items having a `True` value are added to the pool. When multiple conditions are specified in the same call, the conditions are joined by logical `AND` and the resulted assets are added the the pool. `alloc.add()` can be called multiple times which means a logical `OR` relation and add all assets involved to the pool. \n\nOnce candidate assets are determined, Call `alloc.equal_weight()` to assign equal weight in term of value to each selected asset.\n\nAnd finally, call `Strategy.rebalance()`, which will look at the current equity value, calculate the target value for each asset, calculate how many shares to buy or sell based on the current long/short positions, and generate orders that will bring the portfolio to the target allocation.\n\nRun the above strategy on some DJIA components: \n\n![plot of multi-asset strategy](https://imgur.com/ecy6yTm.jpg)\n\n## Trading\n\nTrading a strategy manually is demanding. Running backtest, submitting orders, sticking to the plan despite ups and downs, and tracking performance takes not only effort, but also discipline. Minitrade makes it easy by automating the entire process.\n\nMinitrade's trading system consists of 3 modules:\n1. A scheduler, that runs strategies periodically and triggers order submission.\n2. A broker gateway, that interfaces with the broker system (IB in this case) and handles the communication.\n3. A web UI, that allows managing trading plans and monitoring the executions.\n\n### Launch\n\nTo start trading, run the following:\n\n```\n# start scheduler\nminitrade scheduler start\n\n# start ibgateway\nminitrade ib start \n\n# start web UI\nminitrade web\n```\n\nUse `nohup` or other tools to keep the processes running after quiting the shell.\n\nThe web UI can be accessed at: ```http://127.0.0.1:8501```\n\n![Minitrade web UI - trading](https://imgur.com/1oOPcU7.jpg)\n\n![Minitrade web UI - performance ](https://imgur.com/ofc9k4i.jpg)\n\n### Configure \n\nConfiguring the system takes a few steps:\n\n1. Data source\n\n    Test the data source and make sure it works. Currently only Yahoo is supported. If a proxy is needed to visit Yahoo, configure it in the UI.\n\n2. Broker\n\n    Put in the username and password, and give the account an alias. Note the **Account type** selected is only a hint to help remember. Whether it's paper or live depends on the account itself, rather than on what's chosen here. \n\n    A test connection to the broker is made before the account is saved. It verifies if the credentials are correct and a connection can be established successfully. For IB, if two-factor authentication is enabled, a notification will be sent to the mobile phone. Confirming on the mobile to finish login.\n\n    The credentials are saved in a local database. Be sure to secure the access to the server. \n\n    ![Minitrade web UI - performance ](https://imgur.com/Y0lPTQx.jpg)\n    \n3. Email provider\n\n    Configure a **[Mailjet](https://mailjet.com)** account to receive email notifcations about backtesting and trading results. A free-tier account should be enough. Configure authorized senders in Mailjet, otherwise sending will fail. Try use different domains for senders and receivers if free email services like Hotmail, Gmail are used, otherwise, e.g., an email sending from a Hotmail address, through 3rd part servers, to the same or another Hotmail address is likely to be treated as spam and not delivered. Sending from Hotmail address to Gmail address or vice versa increases the chance of going through. On saving the configuration, a test email will be sent. Setup is successful if the email can be received.\n\n4. Strategy\n\n    Strategies are just Python files containing a strategy class implementation inherited from the `Strategy` class. The files can be uploaded via the UI and be made available for defining a trade plan. If a strategy class can't be found, it will show an error. If multiple strategy classes exist in a file, the one to be run should be decorated with `@entry_strategy`. To update a strategy, upload a differnt file with the same filename.\n\n5. Trade plan\n\n    A trade plan provides all necessary information to trade a strategy, including:\n    - which strategy to run\n    - the universe of assets as a list of tickers\n    - which data source to get price data from\n    - which timezone are the assets traded\n    - which date should a backtest starts\n    - which date should a trade order be generated from\n    - at what time of day should a backtest run \n    - which broker account should orders be submitted through\n    - how much initial cash should be invested\n\n    The generic tickers need to be resolved to broker specific instrument IDs. Therefore a connection to broker will be made, which may trigger 2FA authentication. Pay attention to 2FA push on mobile phone if necessary.\n\n    Once everything is defined, a test backtest dryrun will start. It should finish without error, though it will not generate any actual orders. \n\n    If the test run is successful, the trade plan is scheduled to run every Mon-Fri at the specified time. The time should be between market close and next market open and after when EOD market data becomes available from the selected data source. \n\n    Backtests can be triggered at any time without duplicate orders or any other side effects. \n\n    Backtesting and trading can be enabled or disabled via the UI.\n\n    ![Minitrade web UI - trade plan ](https://imgur.com/Zhrakz5.jpg)\n\n\n### IB gateway\n\nMinitrade uses [IB's client portal API](https://www.interactivebrokers.com/en/trading/ib-api.php#client-portal-api) to submit orders. The gateway client will be automatically downloaded and configured when `minitrade init` is run. It handles automatically login via Chrome and Selenium webdriver. \n\nIB automatically disconnects a session after 24 hours or so. Minitrade checks connection status and reinitializes a connection, if dead, when it needs to interact with IB, i.e. when an order should be submitted or account info is retrieved via web UI. Therefore, 2FA push notification may be sent to mobile phone at random times. If one is missed, try to answer another, which is likely to come on every full 10 minutes in a hour. \n",
    'author': 'Wei Wu',
    'author_email': 'dodid@outlook.com',
    'maintainer': 'None',
    'maintainer_email': 'None',
    'url': 'https://dodid.github.io/minitrade/',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'entry_points': entry_points,
    'python_requires': '>=3.10,<3.11',
}


setup(**setup_kwargs)
