{"id":13744492,"url":"https://github.com/wardbradt/peregrine","last_synced_at":"2025-09-28T23:30:54.445Z","repository":{"id":38375813,"uuid":"119887944","full_name":"wardbradt/peregrine","owner":"wardbradt","description":"Detects arbitrage opportunities across 131 cryptocurrency exchanges in 50 countries","archived":true,"fork":false,"pushed_at":"2021-06-28T20:23:52.000Z","size":4024,"stargazers_count":1190,"open_issues_count":8,"forks_count":339,"subscribers_count":79,"default_branch":"master","last_synced_at":"2024-09-27T03:42:27.975Z","etag":null,"topics":["algorithmic-trading","algotrading","arbitrage","arbitrage-bot","bellman-ford","ccxt","cryptocurrency","python","trading-algorithms","trading-bot"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wardbradt.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-02-01T20:13:22.000Z","updated_at":"2024-09-25T10:15:53.000Z","dependencies_parsed_at":"2022-08-09T03:15:56.229Z","dependency_job_id":null,"html_url":"https://github.com/wardbradt/peregrine","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wardbradt%2Fperegrine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wardbradt%2Fperegrine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wardbradt%2Fperegrine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wardbradt%2Fperegrine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wardbradt","download_url":"https://codeload.github.com/wardbradt/peregrine/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234569826,"owners_count":18854134,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["algorithmic-trading","algotrading","arbitrage","arbitrage-bot","bellman-ford","ccxt","cryptocurrency","python","trading-algorithms","trading-bot"],"created_at":"2024-08-03T05:01:10.516Z","updated_at":"2025-09-28T23:30:53.941Z","avatar_url":"https://github.com/wardbradt.png","language":"Python","funding_links":[],"categories":["Python","Signals","Trading Bots and Bot Frameworks"],"sub_categories":["Arbitrage"],"readme":"# Peregrine\n\nA Python library which provides several algorithms to detect arbitrage opportunities across over 120 cryptocurrency exchanges in 48 countries on over 38,000 trading pairs\n\nI created this in 2017 as a proof-of-concept to familiarize myself with cryptocurrency arbitrage. \nI had fun building it, but do not presently have the bandwidth to maintain the repository. \nThere are some known issues. \nSee the [Future Development](#future-development) section to see current issues and ideas for improvement.\n\n\n### [Install](#install) · [Usage](#usage) · [Future Development](#future-development) \n\n## Install\n1. Ensure you have [installed pip](https://pip.pypa.io/en/stable/installing/).\n2. Run the following in your command line:\n\n    ```\n    pip install git+https://github.com/wardbradt/peregrine\n    ```\n    \n## Usage\n\nThis section provides a brief overview of Peregrine's functionality. Examples demonstrating many more features are available in [peregrine/examples](https://github.com/wardbradt/peregrine/tree/master/examples).\n\n### Multiples Exchange/ One Currency\n\n```python\nfrom peregrinearb import get_opportunity_for_market\nimport asyncio\ncollections_dir = '/Users/wardbradt/cs/peregrine/'\nopportunity = asyncio.get_event_loop().run_until_complete(get_opportunity_for_market(\"BTC/USD\", collections_dir))\nprint(opportunity)\n```\n\nAt the time of writing, this prints the following in less than one second.\n\n```\n{'highest_bid': {'exchange': \u003cccxt.async.lakebtc.lakebtc object at 0x10ea50518\u003e, 'price': 11750.59},\n'lowest_ask': {'exchange': \u003cccxt.async.gdax.gdax object at 0x10ea50400\u003e, 'price': 8450.01}}\n```\n\nIf you want to specify which exchanges to find opportunities on:\n\n```python\nfrom peregrinearb import get_opportunity_for_market\nimport asyncio\n\ncollections_dir = '/Users/wardbradt/cs/peregrine/'\nopportunity = asyncio.get_event_loop().run_until_complete(get_opportunity_for_market(\"BTC/USD\", collections_dir, exchanges=[\"anxpro\", \"bitbay\", \"coinfloor\", \"gemini\", \"livecoin\"]))\nprint(opportunity)\n```\n\nIf you want to find opportunities on the exchanges of only a certain country\u003csup\u003e1\u003c/sup\u003e, you can do it like so:\n\n```python\nfrom peregrinearb import build_specific_collections, get_opportunity_for_market\n\nus_eth_btc_exchanges = build_specific_collections(countries=['US'])\ncollections_dir = '/Users/wardbradt/cs/peregrine/'\nopportunity = get_opportunity_for_market(\"ETH/BTC\", collections_dir, us_eth_btc_exchanges[\"ETH/BTC\"])\nprint(opportunity)\n```\n\n\u003csup\u003e1\u003c/sup\u003eAccepted arguments in place of 'US' in this example are 'PA', 'AU', 'CA', 'JP', 'SG', 'HK', 'NZ', 'IE', 'CN', 'KR', 'IL', 'MT', 'EU', 'VG', 'GB', 'RU', 'PL', 'SC', 'MX', 'NL', 'BR', 'PH', 'UA', 'TR', 'IS', 'TH', 'DE', 'CY', 'CL', 'TW', 'ID', 'UK', 'IN', 'VN', 'BG', 'CZ', 'ES', 'SE', 'VC', 'ZA', 'CH', 'TZ', 'FR', 'AR', 'VE', 'PK', and 'AT'.\n\n### One Exchange/ Multiple Currencies\n\n```python\nimport asyncio\nfrom peregrinearb import load_exchange_graph, print_profit_opportunity_for_path, bellman_ford\ngraph = asyncio.get_event_loop().run_until_complete(load_exchange_graph('hitbtc'))\n\npaths = bellman_ford(graph)\nfor path in paths:\n    print_profit_opportunity_for_path(graph, path)\n```\n\nThis prints all of the arbitrage opportunities on the given exchange (in this case, HitBTC). At the time of writing, the first opportunity printed out is:\n\n```\nStarting with 100 in BTC\nBTC to USDT at 7955.100000 = 795510.000000\nUSDT to NEO at 0.016173 = 12866.084425\nNEO to ETH at 0.110995 = 1428.071041\nETH to XLM at 2709.292875 = 3869062.695088\nXLM to BTC at 0.000026 = 100.208724\n```\nIf you would like to account for transaction fees, set `fees=True` when calling `load_exchange_graph`.\n```python\nimport asyncio\nfrom peregrinearb import load_exchange_graph, print_profit_opportunity_for_path, bellman_ford\n\ngraph = asyncio.get_event_loop().run_until_complete(load_exchange_graph('gdax', fees=True))\n\npaths = bellman_ford(graph)\nfor path in paths:\n    print_profit_opportunity_for_path(graph, path)\n```\n\nTo find the maximum volume that can be used to execute the opportunity, set `depth=True` when calling `bellman_ford`. To my knowledge, the only exchange which offers the functionality of simultaneously fetching the volumes of the top price levels for all markets is Binance.\n```python\nimport asyncio\nfrom peregrinearb import load_exchange_graph, print_profit_opportunity_for_path, bellman_ford\n\ngraph = asyncio.get_event_loop().run_until_complete(load_exchange_graph('binance'))\n\npaths = bellman_ford(graph, depth=True)\nfor path, starting_amount in paths:\n    # Note that depth=True and starting_amount are set in this example\n    print_profit_opportunity_for_path(graph, path, depth=True, starting_amount=starting_amount)\n```\nThis would output:\n```\nStarting with 0.25 in BTC\nBTC to USDT at 7955.100000 = 1988.775\nUSDT to NEO at 0.016173 = 32.1652110625\nNEO to ETH at 0.110995 = 3.5701776025\nETH to XLM at 2709.292875 = 9,672.65673772\nXLM to BTC at 0.000026 = 0.25052181\n```\n### Multiple Exchanges/ Multiple Currencies\n\n```python\nfrom peregrinearb import create_weighted_multi_exchange_digraph, bellman_ford_multi, print_profit_opportunity_for_path_multi\n\n\ngraph = create_weighted_multi_exchange_digraph(['kraken', 'bittrex', 'gemini'], log=True)\ngraph, paths = bellman_ford_multi(graph, 'ETH')\nfor path in paths:\n    print_profit_opportunity_for_path_multi(graph, path)\n```\n\nThis prints all of the arbitrage opportunities on the given exchanges. At the time of writing, the first opportunity printed out is:\n\n```\nStarting with 100 in ETH\nETH to ANT at 204.26088199848851 = 20426.08819984885 on bittrex for ANT/ETH\nANT to BTC at 0.00034417000000000003 = 7.03004677574198 on bittrex for ANT/BTC\nBTC to MLN at 136.57526594618665 = 960.1305080110928 on bittrex for MLN/BTC\nMLN to BTC at 0.0073799999999999985 = 7.085763149121863 on kraken for MLN/BTC\nBTC to GNO at 98.03921568627446 = 694.6826616786137 on bittrex for GNO/BTC\nGNO to BTC at 0.010300000000000002 = 7.155231415289722 on kraken for GNO/BTC\nBTC to GNO at 98.03921568627446 = 701.493276008796 on bittrex for GNO/BTC\nGNO to BTC at 0.010300000000000002 = 7.2253807428906 on kraken for GNO/BTC\nBTC to MLN at 136.57526594618665 = 986.8082965227394 on bittrex for MLN/BTC\nMLN to BTC at 0.0073799999999999985 = 7.282645228337815 on kraken for MLN/BTC\nBTC to USD at 7964.809999999999 = 58004.8855411173 on gemini for BTC/USD\nUSD to ETH at 0.0017965900720432618 = 104.21100149317708 on kraken for ETH/USD\n```\nShould you like to account for transaction fees. In the example above, simply set `fees` to `True` when calling `create_weighted_multi_exchange_digraph`.\nFor example, the following code prints out all of the opportunities found on the given exchanges while accounting for fees:\n```python\nfrom peregrinearb import create_weighted_multi_exchange_digraph, bellman_ford_multi, print_profit_opportunity_for_path_multi\n\n\ngraph = create_weighted_multi_exchange_digraph(['exmo', 'binance', 'bitmex', 'bittrex', 'gemini', 'kraken'], log=True)\n\n\ngraph, paths = bellman_ford_multi(graph, 'ETH', unique_paths=True)\nfor path in paths:\n    print_profit_opportunity_for_path_multi(graph, path)\n```\nThe most profitable of the two printed out is:\n```\nStarting with 100 in ETH\nETH to LTC at 3.2955444239388347 = 329.55444239388345 on binance for LTC/ETH\nLTC to USD at 173.00829999999996 = 57015.65383601369 on exmo for LTC/USD\nUSD to XRP at 1.4110342881332016 = 80451.04252294863 on kraken for XRP/USD\nXRP to USD at 0.739201 = 59469.49108400615 on exmo for XRP/USD\nUSD to BTC at 0.00011205737337516807 = 6.663994966831705 on bitmex for BTC/USD\nBTC to XRP at 12599.218848431392 = 83961.13099195795 on bittrex for XRP/BTC\nXRP to USD at 0.739201 = 62064.15199038631 on exmo for XRP/USD\nUSD to BTC at 0.00011205737337516807 = 6.954745852799899 on bitmex for BTC/USD\nBTC to XRP at 12599.218848431392 = 87624.36503464654 on bittrex for XRP/BTC\nXRP to RUB at 39.120000000000005 = 3427865.160155373 on exmo for XRP/RUB\nRUB to USD at 0.018667164457718873 = 63988.522683505194 on exmo for USD/RUB\nUSD to XRP at 1.4110342881332016 = 90289.99955341498 on kraken for XRP/USD\nXRP to RUB at 39.120000000000005 = 3532144.7825295944 on exmo for XRP/RUB\nRUB to USD at 0.018667164457718873 = 65935.1275439536 on exmo for USD/RUB\nUSD to BCH at 0.000949667616334283 = 62.61645540736334 on kraken for BCH/USD\nBCH to ETH at 1.8874401 = 118.18480885571941 on bittrex for BCH/ETH\n```\n\n## Future Development\nI do not presently actively maintain this project but will respond to issues and pull requests.\n\n### Issues\nSee the repository's [Issues](https://github.com/wardbradt/peregrine/issues) tab for user-submitted issues. At the time of writing, issues I am aware of are:\n- async functionality may be broken\n- some issues with relative paths to generated json files\n\n### Enhancements\n\nImprovements that would be appreciated:\n\n- Prune graph into connected components to improve runtimne\n- Split graph into cycles to find most profitable, instead of any, arbitrage opportunity\n    - A good algorithm to do this is [Johnson's 1975 Cycle-Finding Algorithm](https://www.cs.tufts.edu/comp/150GA/homeworks/hw1/Johnson%2075.PDF)\n- Update requirements and Python version\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwardbradt%2Fperegrine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwardbradt%2Fperegrine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwardbradt%2Fperegrine/lists"}