From 2d1de7437f7e6531c310ef92930e698a4ab1cdb2 Mon Sep 17 00:00:00 2001 From: PolyTrader <82170965+PolyTrader@users.noreply.github.com> Date: Thu, 8 Apr 2021 14:07:05 -0400 Subject: [PATCH 1/5] Initial commit --- .gitignore | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++ LICENSE | 21 +++++++++ README.md | 2 + 3 files changed, 152 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b6e4761 --- /dev/null +++ b/.gitignore @@ -0,0 +1,129 @@ +# 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/ +pip-wheel-metadata/ +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/ + +# 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 +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.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/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bc849a8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 PolyTrader + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d7d4331 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# TradeScroller +(Near) Real-time trades From f6fe632537e6edb7b6eb1f3df0a8edce1c9e6830 Mon Sep 17 00:00:00 2001 From: Buddy Vernon Date: Fri, 9 Apr 2021 23:03:26 -0400 Subject: [PATCH 2/5] gets 5 latest trades and dumps info on latest --- query.gql | 16 ++++++++++++++++ requirements.txt | 2 ++ trade_scroller.py | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) create mode 100644 query.gql create mode 100644 requirements.txt create mode 100644 trade_scroller.py diff --git a/query.gql b/query.gql new file mode 100644 index 0000000..b51bd8e --- /dev/null +++ b/query.gql @@ -0,0 +1,16 @@ +{ + transactions (orderBy: timestamp, orderDirection:desc, first: 5) { + id + type + timestamp + market { + id + } + user { + id + } + tradeAmount + outcomeIndex + outcomeTokensAmount + } +} diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..538aefb --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +requests +gql diff --git a/trade_scroller.py b/trade_scroller.py new file mode 100644 index 0000000..d5610d7 --- /dev/null +++ b/trade_scroller.py @@ -0,0 +1,37 @@ +import json + +import requests +from gql import gql, Client +from gql.transport.requests import RequestsHTTPTransport + + +def markets_by_id(data): + markets = {} + for mkt in data: + markets[mkt["marketMakerAddress"].lower()] = mkt + return markets + + +def main(): + r = requests.get("https://strapi-matic.poly.market/markets?_limit=-1") + if r.status_code != requests.codes.ok: + response.raise_for_status() + + markets = markets_by_id(r.json()) + + transport = RequestsHTTPTransport("https://api.thegraph.com/subgraphs/name/tokenunion/polymarket-matic") + client = Client(transport=transport, fetch_schema_from_transport=True) + + with open("query.gql") as fp: + query = gql(fp.read()) + + result = client.execute(query) + + out_json = json.dumps(result, indent=2) + + print(markets[result['transactions'][0]['market']['id']]['question']) + print(result['transactions'][0]['user']['id']) + print(result['transactions'][0]['tradeAmount']) + +if __name__ == "__main__": + exit(main()) From b743f0a617c251c1a1f30edb74a1724dc19faaa1 Mon Sep 17 00:00:00 2001 From: Buddy Vernon Date: Sun, 11 Apr 2021 14:45:41 -0400 Subject: [PATCH 3/5] working poc --- query.gql | 4 +-- trade_scroller.py | 62 ++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/query.gql b/query.gql index b51bd8e..c2d1125 100644 --- a/query.gql +++ b/query.gql @@ -1,5 +1,5 @@ -{ - transactions (orderBy: timestamp, orderDirection:desc, first: 5) { +query latestTransactions ($ts: BigInt!) { + transactions (orderBy: timestamp, orderDirection:desc, where: {timestamp_gt: $ts}) { id type timestamp diff --git a/trade_scroller.py b/trade_scroller.py index d5610d7..1d82bf7 100644 --- a/trade_scroller.py +++ b/trade_scroller.py @@ -1,4 +1,6 @@ import json +from datetime import datetime, timedelta +from time import sleep import requests from gql import gql, Client @@ -12,26 +14,62 @@ def markets_by_id(data): return markets +def gql_query(timestamp): + transport = RequestsHTTPTransport("https://api.thegraph.com/subgraphs/name/tokenunion/polymarket-matic") + client = Client(transport=transport, fetch_schema_from_transport=True) + + with open("query.gql") as fp: + query = gql(fp.read()) + + return client.execute(query, {"ts": timestamp}) + + +def show_transaction(trx, mkt, count): + print(f"# {count} # ****************************************") + print(mkt['question']) + print(f"Id: {trx['id']}") + print(f"User: {trx['user']['id']}") + + amount = float(trx['tradeAmount']) / 1000000 + print(f"Amout: ${amount}") + + ts = int(trx['timestamp']) + print(f"Timestamp: {datetime.utcfromtimestamp(ts)}") + + outcomeIndex = int(trx['outcomeIndex']) + outcome = mkt['outcomes'][outcomeIndex] + + buy_or_sell = trx['type'] + + print(f"Action: {buy_or_sell} {outcome}") + + num_shares = float(trx['outcomeTokensAmount']) / 1000000 + + print(f"#shares: {num_shares}") + + def main(): - r = requests.get("https://strapi-matic.poly.market/markets?_limit=-1") + r = requests.get("https://strapi-matic.poly.market/markets?_limit=-1&active=true") if r.status_code != requests.codes.ok: response.raise_for_status() markets = markets_by_id(r.json()) - transport = RequestsHTTPTransport("https://api.thegraph.com/subgraphs/name/tokenunion/polymarket-matic") - client = Client(transport=transport, fetch_schema_from_transport=True) - - with open("query.gql") as fp: - query = gql(fp.read()) - - result = client.execute(query) + count = 0 + timestamp = int(datetime.now().timestamp()) + while True: + result = gql_query(timestamp) - out_json = json.dumps(result, indent=2) + for trx in result['transactions']: + mkt = markets[trx['market']['id']] + show_transaction(trx, mkt, count) + count += 1 - print(markets[result['transactions'][0]['market']['id']]['question']) - print(result['transactions'][0]['user']['id']) - print(result['transactions'][0]['tradeAmount']) + try: + timestamp = trx['timestamp'] + except: + pass + sleep(2.0) if __name__ == "__main__": exit(main()) From e63467254a8813da0a77d31443040546b723aa39 Mon Sep 17 00:00:00 2001 From: NicholasQ Date: Sun, 11 Apr 2021 15:29:25 -0400 Subject: [PATCH 4/5] Add watchlist Adds a watchlist.txt file. If the file is empty then tradescroller shows all trades. If there are question names in the watchlist , then only trades in questions in the watchlist will be displayed. The watchlist is the market question names seperated by newlines. --- trade_scroller.py | 16 +++++++++++++--- watchlist.txt | 0 2 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 watchlist.txt diff --git a/trade_scroller.py b/trade_scroller.py index 1d82bf7..34334e2 100644 --- a/trade_scroller.py +++ b/trade_scroller.py @@ -55,14 +55,24 @@ def main(): markets = markets_by_id(r.json()) + try: + with open("watchlist.txt") as f: + watchlist = f.read().splitlines() + except: + watchlist = False + count = 0 timestamp = int(datetime.now().timestamp()) while True: result = gql_query(timestamp) - for trx in result['transactions']: - mkt = markets[trx['market']['id']] - show_transaction(trx, mkt, count) + for trx in result["transactions"]: + mkt = markets[trx["market"]["id"]] + if watchlist: + if mkt["question"] in watchlist: + show_transaction(trx, mkt, count) + else: + show_transaction(trx, mkt, count) count += 1 try: diff --git a/watchlist.txt b/watchlist.txt new file mode 100644 index 0000000..e69de29 From acbbaf5055aac1d5ded5b0629635066464dd254c Mon Sep 17 00:00:00 2001 From: NicholasQ <83617214+MarbleMonkey@users.noreply.github.com> Date: Thu, 6 May 2021 22:11:34 -0400 Subject: [PATCH 5/5] Add alias list Adds aliases.csv which is a list of aliases for different addresses in the format: address, alias These replace the address that is displayed to make it easier to recognize. --- aliases.csv | 0 trade_scroller.py | 28 ++++++++++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 aliases.csv diff --git a/aliases.csv b/aliases.csv new file mode 100644 index 0000000..e69de29 diff --git a/trade_scroller.py b/trade_scroller.py index 34334e2..a60fc0e 100644 --- a/trade_scroller.py +++ b/trade_scroller.py @@ -1,4 +1,5 @@ import json +import csv from datetime import datetime, timedelta from time import sleep @@ -24,13 +25,22 @@ def gql_query(timestamp): return client.execute(query, {"ts": timestamp}) -def show_transaction(trx, mkt, count): +def show_transaction(trx, mkt, count, aliases): print(f"# {count} # ****************************************") print(mkt['question']) print(f"Id: {trx['id']}") - print(f"User: {trx['user']['id']}") - - amount = float(trx['tradeAmount']) / 1000000 + user_address = trx["user"]["id"] + if aliases: + username = next((i[1] for i in aliases if i[0] == user_address), None) + else: + username = None + + if username: + print(f"User: {username}") + else: + print(f"User: {user_address}") + + amount = float(trx["tradeAmount"]) / 1000000 print(f"Amout: ${amount}") ts = int(trx['timestamp']) @@ -61,6 +71,12 @@ def main(): except: watchlist = False + try: + with open("aliases.csv") as f: + aliases = list(csv.reader(f)) + except: + aliases = False + count = 0 timestamp = int(datetime.now().timestamp()) while True: @@ -70,9 +86,9 @@ def main(): mkt = markets[trx["market"]["id"]] if watchlist: if mkt["question"] in watchlist: - show_transaction(trx, mkt, count) + show_transaction(trx, mkt, count, aliases) else: - show_transaction(trx, mkt, count) + show_transaction(trx, mkt, count, aliases) count += 1 try: