{ "info": { "author": "nuric", "author_email": "nuric@users.noreply.github.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "License :: OSI Approved :: Apache Software License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python :: 3 :: Only", "Topic :: Office/Business :: Financial" ], "description": "# :chart_with_upwards_trend: pedlar\nPedlar is an algorithmic trading platform for Python designed for trading events, competitions and sessions such as Algothons. It includes a live web interface with multiple accounts with account sharing and live chat, an HTTP API with example Python trading agents and a [ZeroMQ](http://zeromq.org/) based broker connection to [MetaTrader5](https://www.metatrader5.com/en).\n\n![pedlarweb](https://raw.githubusercontent.com/nuric/pedlar/master/pedlarweb_screenshot.jpg)\n\n## Getting Started\nIf there is already a ticker server and web server running, the client API under `pedlar` can be used. If not, follow instructions on how to get them in the [Hosting](#hosting) section. The client or *agent* API resolves around connecting to the *ticker* server (where agents receive price updates) and the *web* server, in this case handles the broker connection. The ticker is separate to reduce overhead and latencies between making trades and just receiving price updates.\n\n### Installation\nThe client API is can be installed using:\n\n```bash\npip3 install --no-cache-dir -U pedlar\n```\n\n### Usage\nThere are some helpful examples in the `pedlar` folder. Here is a overview of the client API:\n\n```python\nfrom pedlar.agent import Agent\n\nclass MyAgent(Agent):\n \"\"\"A trading agent.\"\"\"\n def on_order(self, order):\n \"\"\"Called on placing a new order.\"\"\"\n print(\"New order:\", order)\n print(\"Orders:\", self.orders) # Agent orders only\n\n def on_order_close(self, order, profit):\n \"\"\"Called on closing an order with some profit.\"\"\"\n print(\"Order closed\", order, profit)\n print(\"Current balance:\", self.balance) # Agent balance only\n\n def on_tick(self, bid, ask, time=None):\n \"\"\"Called on every tick update.\"\"\"\n print(\"Tick:\", bid, ask, time)\n # self.buy()\n # self.sell()\n # self.close()\n\n def on_bar(self, bopen, bhigh, blow, bclose, time=None):\n \"\"\"Called on every bar update.\"\"\"\n print(\"Bar:\", bopen, bhigh, blow, bclose, time)\n\nif __name__ == \"__main__\":\n import logging\n logging.basicConfig(level=logging.DEBUG)\n agent = MyAgent.from_args()\n agent.run()\n```\n\nThe extra parameters are parsed from the command line and can be run using:\n\n```bash\npython3 -u myagent.py -h\n```\n\nKey things to keep in mind:\n\n - Every agent takes control of its own orders and balance, it is *not synced* across agents of a shared account. This setup is to keep agents isolated.\n - Agents try to close orders when they are quit, if hard stopped or an error occurs an open orphan order might remain. In this case, one option would be manually invoke `self.close` with the stale order id or simply reset the account.\n - The ticker connection receives from ZeroMQ whereas the trade requests are made via HTTP. There might some ticks dropped if the trade request takes too long.\n\n### Basic Backtesting\nThe agents can backtest against a CSV file of the following format, last column time is optional and time format is adjustable through `time_format` of the `Agent` class:\n\n```\ntick,1.26361,1.26375,2019.01.03 23:44:42\ntick,1.2636,1.26374,2019.01.03 23:44:59\ntick,1.2636,1.26378,2019.01.03 23:45:00\nbar,1.26386,1.26398,1.26355,1.2636,2019.01.03 23:45:00\ntick,1.26359,1.26377,2019.01.03 23:45:02\ntick,1.26357,1.26375,2019.01.03 23:45:05\ntick,1.26356,1.26374,2019.01.03 23:45:07\ntick,1.26358,1.26376,2019.01.03 23:45:10\n```\n\nwhich can be used with an agent `python3 myagent.py -b ticks.csv`. Essentially each line will invoke corresponding `on_tick` or `on_bar` function. **The actual profit and trade results are computed offline based on absolute price differences.** This means the agent will run completely offline and the actual results are only useful to get an idea about the performance or train a neural network. Any extra broker commissions beyond bid-ask spread, price requotes etc are not factored.\n\n## Hosting\nPedlar involves 4 components that talk to each other to create a platform for agents to trade:\n\n - **ticker:** is a ZeroMQ `PUB` socket that publishes tick and bar updates that are received by the agents which eventually trigger `on_tick` and `on_bar` methods. This component runs independently from others to provide a continuous stream of price updates.\n - **broker:** is the component that actually executes live order requests on the market. Pedlar is broker agnostic and all it needs is methods to buy, sell and close an order with unique order ids.\n - **pedlarweb**: is the main web server that handles user accounts, live leaderboard etc updates and agent trade requests.\n - **pedlar**: is the client API that allows for Python based clients to receive updates from *ticker* and make trade requests to *pedlarweb*.\n\n### Repository Structure\nThe client and server packages are separated to avoid any assumptions between their implementations. The main folders include:\n\n - **mt5:** contains the MetaTrader 5 trading components that act as the *ticker* and the *broker* for live trading.\n - **pedlar:** contains the client API is the exposed API for building new agents.\n - **pedlarweb:** is the web server that bridges agent trade requests and broker while providing a web user interface and live updates.\n\n### Prerequisites\nAll the extra packages required can be installed using:\n```bash\npip3 install --no-cache-dir -U -r requirements.txt\n```\n\n### Running MT5\nTo get the ticker and broker components up and running you need to:\n\n 1. [Install MetaTrader 5](https://www.metatrader5.com/en/download), or some existing installation would work.\n 2. [Install ZeroMQ](http://zeromq.org/distro:microsoft-windows) for Windows since the scripts require the `libzmq.dll` to run. You might need to install a compatible [Visual C++](https://support.microsoft.com/en-gb/help/2977003/the-latest-supported-visual-c-downloads) runtime to get ZeroMQ running.\n 3. Find the installed ZeroMQ `bin` folder and move the DLL to `Library\\libzmq.dll` as that is where the `libzmq.mqh` header expects it.\n 4. Copy files MetaTrader 5 files to the expected folders of your installation. An easy way to find that is to open the MetaEditor (F4 from trader) and right click on a folder to select *Open Folder*. For development it is easier to write a script that syncs the repo folder with the expected folders.\n 5. Once the ticker and broker is compiled, you can attach them to any chart that you want the tick updates to be sent and trade orders to be handled. You can run multiple at different ports as well. From \"Options\" the \"Allow DLL Imports\" needs to be enabled for obvious reasons.\n 6. If you get DLL import error, it is most likely because the ZeroMQ DLL isn't happy or the C++ runtime is not compatible.\n\n\n### Running Local Broker\nAs an alternative to executing trades live, there is `lbroker.py` that implements same interface as the actual MT5 broker but instead executes the orders locally based on the latest ticks provided by MT5. It is a simple stand-alone script:\n\n```bash\npython3 lbroker.py -h\n```\n\n### Running Web Server\nThe web server is a standard [Flask](http://flask.pocoo.org/) application organised into the `pedlarweb` package. You need to create a `instance/config.py` to customise the default values. Once the `config.py` options are as desired, a database can be initialised:\n\n```bash\nmkdir instance && cp config.py instance/config.py # customise instance/config.py ex. database settings\npython3 -c \"from pedlarweb import db; db.create_all()\"\n```\n\nIf the in-memory default database is used, tables will be automatically created but *data is lost when server is stopped using an in-memory database.* Then the server can be run using standard Flask options:\n\n```bash\npython3 runpedlarweb.py -h\n\nusage: runpedlarweb.py [-h] [-d] [--host HOST] [--port PORT]\n\nRun pedlarweb.\n\noptional arguments:\n -h, --help show this help message and exit\n -d, --debug Enable debug server.\n --host HOST Host IP address.\n --port PORT Host port.\n```\n\nDue to [Flask-SocketIO](https://flask-socketio.readthedocs.io/en/latest/) the `eventlet` server would be run. **For convinience, a new user is created if none with the username exist from the login page.** This choice is done to get people on-board as easy as possible without heavy registration and email confirmation schemes.\n\n## FAQ\n\n - **Why ticker is separated from the web server?** This design choice is done to reduce overhead and latency in receiving price updates for agents. As a result agents need to connect to both the ticker and the web server to function unless backtesting.\n - **Why not use ZeroMQ for trade requests instead of HTTP?** HTTP APIs provide a more approachable and unified way of providing a service. HTTP does have more overhead but it makes it easier for other non-pedlar clients that talk to `pedlarweb` to be built as well. Finally, it has an authentication mechanism that is enforced for every request.\n - **Why is the source code 2 space indented?** The answer is a combination of personal style and to stop direct copy-paste from other resources. The code is linted using [PyLint](https://www.pylint.org/) although there are cases it is disabled on purpose.\n\n## Limitations & To-Dos\n\n - Currently the API *supports trading only on a single instrument* mainly because the web server can talk to a single broker and a single broker can only be attached to single chart. The MT5 broker is fixed to the current chart `Symbol()` but there is space for passing the symbol, instrument from agent -> server -> broker. For the target audience of live sessions and competitions, a single instrument seems enough.\n - Although polling is employed for ZeroMQ sockets, they are still *blocking* in nature to avoid data loss. In that case, an agent can look like it has frozen against Ctrl+C. This case also occurs for MT5 ticker and broker scripts. The timeout on the polls can be adjust or a little patience helps.\n - There is a mixture of line endings due MT5 running on Windows and development is somewhat split between Windows and Linux environments. Hopefully, we live in a day and age this is not a problem anymore.\n\n## Built With\n\n - [Flask](http://flask.pocoo.org/) - `pedlarweb` web framework\n - [ZeroMQ](http://zeromq.org/) - `ticker` and `broker` messaging framework\n - [MetaTrader5](https://www.metatrader5.com/en) - as the default trading platform\n - [SocketIO](https://socket.io/) - server client messaging for dynamic updates\n - [Vue.JS](https://vuejs.org/) - dynamic front-end rendering\n - [W3.CSS](https://www.w3schools.com/w3css/) - front-end CSS library\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/nuric/pedlar", "keywords": "", "license": "", "maintainer": "", "maintainer_email": "", "name": "pedlar", "package_url": "https://pypi.org/project/pedlar/", "platform": "", "project_url": "https://pypi.org/project/pedlar/", "project_urls": { "Homepage": "https://github.com/nuric/pedlar" }, "release_url": "https://pypi.org/project/pedlar/0.0.8/", "requires_dist": [ "pyzmq", "requests" ], "requires_python": "", "summary": "Algorithmic Trading Platform for Python", "version": "0.0.8" }, "last_serial": 5849301, "releases": { "0.0.2": [ { "comment_text": "", "digests": { "md5": "23f1d05da6323cdbb3d2a9cf238ac0d9", "sha256": "4e002826b00e41dcc4754fd45c23c22437c487fc4d3c61075f0f0ebce26da1d8" }, "downloads": -1, "filename": "pedlar-0.0.2-py3-none-any.whl", "has_sig": false, "md5_digest": "23f1d05da6323cdbb3d2a9cf238ac0d9", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 10637, "upload_time": "2018-09-23T10:34:59", "url": "https://files.pythonhosted.org/packages/99/34/a5de0a484b79a930cc8daf5defd47d1d9f3c5cac7060af2e8be7b3407b33/pedlar-0.0.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "b64e75d0432518a45b655f616262fc15", "sha256": "ad4db81356f09f846ac06f553dd2143a6a94e3678f8ab2c9c33406eaa2e62cfd" }, "downloads": -1, "filename": "pedlar-0.0.2.tar.gz", "has_sig": false, "md5_digest": "b64e75d0432518a45b655f616262fc15", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9633, "upload_time": "2018-09-23T10:35:00", "url": "https://files.pythonhosted.org/packages/75/16/c10a2a865dd333cf6bc806ed17e2084bd083edbb3d5ade5952fc32ae3fa7/pedlar-0.0.2.tar.gz" } ], "0.0.3": [ { "comment_text": "", "digests": { "md5": "69e4bea9c673dcff0edf9fa299935a69", "sha256": "62214509b62ccfc1fcc01ceac29c45b2fa4066cfe9bd081023131343c9d7ea75" }, "downloads": -1, "filename": "pedlar-0.0.3-py3-none-any.whl", "has_sig": false, "md5_digest": "69e4bea9c673dcff0edf9fa299935a69", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 10785, "upload_time": "2018-09-28T12:08:29", "url": "https://files.pythonhosted.org/packages/83/cb/fa9a2c083e688fd96bf55dd07112e45e1edb62e0be7d596c32045ff0b4cc/pedlar-0.0.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "2c6a8c626090192f8529ad879318c024", "sha256": "82975af4a2b86aae77cf1e1337cd570676a5103db7bc743a468487361bf576c6" }, "downloads": -1, "filename": "pedlar-0.0.3.tar.gz", "has_sig": false, "md5_digest": "2c6a8c626090192f8529ad879318c024", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9812, "upload_time": "2018-09-28T12:08:31", "url": "https://files.pythonhosted.org/packages/5e/9f/d822de1de48d9b22a65f108e6725b35d4bada2be123d8c37493d7d8546e8/pedlar-0.0.3.tar.gz" } ], "0.0.4": [ { "comment_text": "", "digests": { "md5": "52c32e32a4c50b0a392f5bbfadf128c8", "sha256": "4a5db802fe3cc1c86e51fe7283fb73821813903488e6dd2292024d9c2c36a202" }, "downloads": -1, "filename": "pedlar-0.0.4-py3-none-any.whl", "has_sig": false, "md5_digest": "52c32e32a4c50b0a392f5bbfadf128c8", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 10807, "upload_time": "2018-10-01T22:08:13", "url": "https://files.pythonhosted.org/packages/44/82/04ef1e6eeec0ad7802ec7f31f36b773da5a05da3979b04b6a72897d1a607/pedlar-0.0.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9e48fca7cbed33ff3192e2b43c02c5bf", "sha256": "d75eefe59df54cd61ebe4bf1cb5a5569f288a115b521c0cc7610a4d7a90ab7e7" }, "downloads": -1, "filename": "pedlar-0.0.4.tar.gz", "has_sig": false, "md5_digest": "9e48fca7cbed33ff3192e2b43c02c5bf", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9835, "upload_time": "2018-10-01T22:08:16", "url": "https://files.pythonhosted.org/packages/0f/5e/7c7fe12664ba2c9638ae2912ca0a4ece7ce283d0e8167e99aa11f3642611/pedlar-0.0.4.tar.gz" } ], "0.0.5": [ { "comment_text": "", "digests": { "md5": "5c81bc426daf49a6c3002ed9151c6159", "sha256": "9f82a5997656dd51b867021436e58375b2ec4d34c6d1263e3db2102fb9766bbc" }, "downloads": -1, "filename": "pedlar-0.0.5-py3-none-any.whl", "has_sig": false, "md5_digest": "5c81bc426daf49a6c3002ed9151c6159", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 10871, "upload_time": "2018-10-06T22:47:30", "url": "https://files.pythonhosted.org/packages/f4/b7/94555f276ef329285101362306c9305bdda75960709e7fc0bd9421617a09/pedlar-0.0.5-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "30f8bc99b779a36a746b7a76b10f8c99", "sha256": "35cf2992d25cb73427b1d434925cc26ceabed89eb661cc136418849ea490ea5c" }, "downloads": -1, "filename": "pedlar-0.0.5.tar.gz", "has_sig": false, "md5_digest": "30f8bc99b779a36a746b7a76b10f8c99", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9917, "upload_time": "2018-10-06T22:47:33", "url": "https://files.pythonhosted.org/packages/83/f2/172cf421dd5ce2c67854407729911b53ccd3b9adc890ef66e053cbd6bedb/pedlar-0.0.5.tar.gz" } ], "0.0.6": [ { "comment_text": "", "digests": { "md5": "5bb7baa8cec7daf1dd70c72580b38d89", "sha256": "6658fc49cc034e4bd33cc60e7678b330945d71104a3aa47ae744bb4e52d7eaa6" }, "downloads": -1, "filename": "pedlar-0.0.6-py3-none-any.whl", "has_sig": false, "md5_digest": "5bb7baa8cec7daf1dd70c72580b38d89", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 11049, "upload_time": "2018-10-16T11:53:57", "url": "https://files.pythonhosted.org/packages/f8/08/9594ac750fd3313b290c17987232736ce9b6829f4f62a55b8d024bb60c73/pedlar-0.0.6-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d3e98340bbec111d3e4dde26dfa2be2f", "sha256": "0a2ed227cc7daafa4b0487f551999626d4f8910da6f9b5acba372b37c7443710" }, "downloads": -1, "filename": "pedlar-0.0.6.tar.gz", "has_sig": false, "md5_digest": "d3e98340bbec111d3e4dde26dfa2be2f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10154, "upload_time": "2018-10-16T11:54:00", "url": "https://files.pythonhosted.org/packages/39/ed/3a38fbc0a83b0b282491ca671418271ae15c9d8945ff634cb5a8e6dc3f6a/pedlar-0.0.6.tar.gz" } ], "0.0.7": [ { "comment_text": "", "digests": { "md5": "0d63a0697b244f7551ae26eb8a65e098", "sha256": "9de82858fd53ae635ce7b36f6e4006770bf0447e16efdc856e9e8920c5c5771c" }, "downloads": -1, "filename": "pedlar-0.0.7-py3-none-any.whl", "has_sig": false, "md5_digest": "0d63a0697b244f7551ae26eb8a65e098", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 15448, "upload_time": "2019-01-05T14:15:57", "url": "https://files.pythonhosted.org/packages/c4/7f/c6cd37932355f1ceec37c233ffe645eb87dd1cf05a5ebb9037ae765377d7/pedlar-0.0.7-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "ebdc061e350abaa035eefa68e9d96424", "sha256": "86887e750b363e8e65db38b3472105510ce5cb06eed06879b078b53cac987a4d" }, "downloads": -1, "filename": "pedlar-0.0.7.tar.gz", "has_sig": false, "md5_digest": "ebdc061e350abaa035eefa68e9d96424", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10374, "upload_time": "2019-01-05T14:16:00", "url": "https://files.pythonhosted.org/packages/63/2d/b61cd1a0009f9e0927ea93fbac6b58c648c29253e32b55f04a6261a220ba/pedlar-0.0.7.tar.gz" } ], "0.0.8": [ { "comment_text": "", "digests": { "md5": "78746dc99c4285c0c0d26bfcf06779ff", "sha256": "0d09f3081ed6372f0746b8fab85ab166f2cfbce2e16b9e0ab707fc6f2bf61d8a" }, "downloads": -1, "filename": "pedlar-0.0.8-py3-none-any.whl", "has_sig": false, "md5_digest": "78746dc99c4285c0c0d26bfcf06779ff", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 16068, "upload_time": "2019-09-18T10:52:06", "url": "https://files.pythonhosted.org/packages/85/af/fe6bdc1c8a74ca6b91d1551c87439bb0f1184b47b684b47a8438ac27d796/pedlar-0.0.8-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "af3efd2fa446bb97886b98ad0e5b48f2", "sha256": "7504b5d6a6dc44190b6b3a1a92e71c47938bb03cffcf1bd8ae2313cbebcdb700" }, "downloads": -1, "filename": "pedlar-0.0.8.tar.gz", "has_sig": false, "md5_digest": "af3efd2fa446bb97886b98ad0e5b48f2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10843, "upload_time": "2019-09-18T10:52:15", "url": "https://files.pythonhosted.org/packages/5c/23/8a1680d6e3c0308286aa3a870f7454fc28d09a9d048be75f688a4d8e8602/pedlar-0.0.8.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "78746dc99c4285c0c0d26bfcf06779ff", "sha256": "0d09f3081ed6372f0746b8fab85ab166f2cfbce2e16b9e0ab707fc6f2bf61d8a" }, "downloads": -1, "filename": "pedlar-0.0.8-py3-none-any.whl", "has_sig": false, "md5_digest": "78746dc99c4285c0c0d26bfcf06779ff", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 16068, "upload_time": "2019-09-18T10:52:06", "url": "https://files.pythonhosted.org/packages/85/af/fe6bdc1c8a74ca6b91d1551c87439bb0f1184b47b684b47a8438ac27d796/pedlar-0.0.8-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "af3efd2fa446bb97886b98ad0e5b48f2", "sha256": "7504b5d6a6dc44190b6b3a1a92e71c47938bb03cffcf1bd8ae2313cbebcdb700" }, "downloads": -1, "filename": "pedlar-0.0.8.tar.gz", "has_sig": false, "md5_digest": "af3efd2fa446bb97886b98ad0e5b48f2", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10843, "upload_time": "2019-09-18T10:52:15", "url": "https://files.pythonhosted.org/packages/5c/23/8a1680d6e3c0308286aa3a870f7454fc28d09a9d048be75f688a4d8e8602/pedlar-0.0.8.tar.gz" } ] }