Skip to content
This repository was archived by the owner on Oct 5, 2021. It is now read-only.

Commit ad0b3f1

Browse files
committed
moving to pairtypes, working subscription to multiple currency pairs
1 parent ec9f2ce commit ad0b3f1

File tree

19 files changed

+214
-61
lines changed

19 files changed

+214
-61
lines changed

algocoin/backtest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from .lib.logging import LOG as log, DATA as dlog
44
from .lib.structs import MarketData
55
from .lib.utils import parse_date
6-
from .lib.enums import CurrencyType, TickType, Side
6+
from .lib.enums import PairType, TickType, Side
77

88

99
class Backtest(StreamingDataSource):
@@ -32,7 +32,7 @@ def receive(self, line: str) -> None:
3232
price=float(res[1]),
3333
volume=float(res[2]),
3434
type=TickType.TRADE,
35-
currency=CurrencyType.BTC,
35+
currency_pair=PairType.BTCUSD,
3636
side=Side.NONE)
3737

3838
if data.type == TickType.TRADE:

algocoin/lib/config.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
from .utils import config
2-
from .enums import TradingType, ExchangeType
2+
from .enums import TradingType, ExchangeType, PairType
33

44

55
@config
66
class ExchangeConfig:
77
exchange_type = ExchangeType, ExchangeType.NONE
88
exchange_types = [ExchangeType], []
99
trading_type = TradingType, TradingType.NONE
10+
currency_pairs = [PairType], [PairType.BTCUSD]
1011

1112

1213
@config

algocoin/lib/define.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
(ExchangeType.CEX, TradingType.LIVE): '',
1111
(ExchangeType.GDAX, TradingType.SANDBOX): 'wss://ws-feed.sandbox.gdax.com',
1212
(ExchangeType.GDAX, TradingType.LIVE): 'wss://ws-feed.gdax.com',
13+
(ExchangeType.COINBASE, TradingType.SANDBOX): 'wss://ws-feed.pro.pro.coinbase.com',
14+
(ExchangeType.COINBASE, TradingType.LIVE): 'wss://ws-feed.pro.coinbase.com',
1315
(ExchangeType.GEMINI, TradingType.SANDBOX): 'wss://api.sandbox.gemini.com/v1/marketdata/btcusd?heartbeat=true',
1416
(ExchangeType.GEMINI, TradingType.LIVE): 'wss://api.gemini.com/v1/marketdata/btcusd?heartbeat=true',
1517
(ExchangeType.HITBTC, TradingType.SANDBOX): '',
@@ -33,6 +35,8 @@
3335
(ExchangeType.CEX, TradingType.LIVE): '',
3436
(ExchangeType.GDAX, TradingType.SANDBOX): 'https://api-public.sandbox.gdax.com',
3537
(ExchangeType.GDAX, TradingType.LIVE): 'https://api.gdax.com',
38+
(ExchangeType.COINBASE, TradingType.SANDBOX): 'https://api-public.sandbox.pro.coinbase.com',
39+
(ExchangeType.COINBASE, TradingType.LIVE): 'https://api.pro.coinbase.com',
3640
(ExchangeType.GEMINI, TradingType.SANDBOX): 'https://api.sandbox.gemini.com/v1/marketdata/btcusd?heartbeat=true',
3741
(ExchangeType.GEMINI, TradingType.LIVE): 'https://api.gemini.com/v1/marketdata/btcusd?heartbeat=true',
3842
(ExchangeType.HITBTC, TradingType.SANDBOX): '',

algocoin/lib/enums.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class ExchangeType(BaseEnum):
3434
BITFINEX = 2
3535
CEX = 3
3636
GDAX = 4
37+
COINBASE = 11
3738
GEMINI = 5
3839
HITBTC = 6
3940
ITBIT = 7
@@ -47,6 +48,41 @@ class CurrencyType(BaseEnum):
4748
BTC = 1
4849
ETH = 2
4950
LTC = 3
51+
BCH = 4
52+
ZEC = 5
53+
54+
55+
class PairType(BaseEnum):
56+
# USD Pairs
57+
USDBTC = (CurrencyType.USD, CurrencyType.BTC)
58+
USDETH = (CurrencyType.USD, CurrencyType.ETH)
59+
USDLTC = (CurrencyType.USD, CurrencyType.LTC)
60+
USDBCH = (CurrencyType.USD, CurrencyType.BCH)
61+
USDZEC = (CurrencyType.USD, CurrencyType.ZEC)
62+
63+
# BTC Pairs
64+
BTCUSD = (CurrencyType.BTC, CurrencyType.USD)
65+
BTCETH = (CurrencyType.BTC, CurrencyType.ETH)
66+
BTCLTC = (CurrencyType.BTC, CurrencyType.LTC)
67+
BTCBCH = (CurrencyType.BTC, CurrencyType.BCH)
68+
BTCZEC = (CurrencyType.BTC, CurrencyType.ZEC)
69+
70+
# ETH Pairs
71+
ETHUSD = (CurrencyType.ETH, CurrencyType.USD)
72+
ETHBTC = (CurrencyType.ETH, CurrencyType.BTC)
73+
74+
# LTC Pairs
75+
LTCUSD = (CurrencyType.LTC, CurrencyType.USD)
76+
LTCBTC = (CurrencyType.LTC, CurrencyType.BTC)
77+
78+
# BCH Pairs
79+
BCHUSD = (CurrencyType.BCH, CurrencyType.USD)
80+
BCHBTC = (CurrencyType.BCH, CurrencyType.BTC)
81+
82+
# ZEC Pairs
83+
ZECUSD = (CurrencyType.ZEC, CurrencyType.USD)
84+
ZECBTC = (CurrencyType.ZEC, CurrencyType.BTC)
85+
ZECETH = (CurrencyType.ZEC, CurrencyType.ETH) # Gemini
5086

5187

5288
class Side(BaseEnum):

algocoin/lib/exchanges/gdax.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ def __init__(self, options: ExchangeConfig) -> None:
2727

2828
elif options.trading_type == TradingType.SANDBOX:
2929
self._key, self._secret, self._passphrase = get_keys_from_environment('GDAX_SANDBOX')
30-
import ipdb; ipdb.set_trace()
3130
self._client = gdax.AuthenticatedClient(self._key,
3231
self._secret,
3332
self._passphrase,
@@ -48,12 +47,12 @@ def __init__(self, options: ExchangeConfig) -> None:
4847
account = Account(id=id, currency=currency, balance=balance)
4948
self._accounts.append(account)
5049

51-
self._subscription = json.dumps({"type": "subscribe",
52-
"product_id": "BTC-USD"})
50+
self._subscription = [json.dumps({"type": "subscribe",
51+
"product_id": GDAXExchange.currency_pair_to_string(x)}) for x in options.currency_pairs]
5352
self._heartbeat = json.dumps({"type": "heartbeat",
5453
"on": True})
5554

56-
self._seqnum_enabled = True
55+
self._seqnum_enabled = False # FIXME?
5756

5857
def run(self, engine) -> None:
5958
# DEBUG
@@ -66,8 +65,9 @@ def run(self, engine) -> None:
6665
self.ws = create_connection(self._md_url)
6766
log.info('Connected!')
6867

69-
self.ws.send(self._subscription)
70-
log.info('Sending Subscription %s' % self._subscription)
68+
for sub in self._subscription:
69+
self.ws.send(sub)
70+
log.info('Sending Subscription %s' % sub)
7171
self.ws.send(self._heartbeat)
7272
log.info('Sending Heartbeat %s' % self._heartbeat)
7373

@@ -128,7 +128,7 @@ def buy(self, req: TradeRequest) -> TradeResponse:
128128
side=req.side,
129129
volume=float(order['filled_size']),
130130
price=float(order['price']),
131-
currency=req.currency,
131+
currency_pair=req.currency_pair,
132132
slippage=slippage,
133133
transaction_cost=txn_cost,
134134
status=status,

algocoin/lib/exchanges/helpers.py

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from datetime import datetime
2-
from ..enums import CurrencyType, OrderType, OrderSubType, Side
3-
from ..utils import parse_date, str_to_currency_type, str_to_side, \
2+
from ..enums import OrderType, OrderSubType, Side, PairType, CurrencyType
3+
from ..utils import parse_date, str_to_currency_type, str_to_currency_pair_type, str_to_side, \
44
str_to_order_type
55
from ..structs import MarketData
66
from ..enums import TickType
@@ -13,19 +13,18 @@ def tickToData(jsn: dict) -> MarketData:
1313
price = float(jsn.get('price', 'nan'))
1414
volume = float(jsn.get('size', 'nan'))
1515
typ = GDAXHelpersMixin.strToTradeType(jsn.get('type'))
16-
currency = str_to_currency_type(jsn.get('product_id'))
16+
currency_pair = str_to_currency_pair_type(jsn.get('product_id'))
1717

1818
order_type = str_to_order_type(jsn.get('order_type', ''))
1919
side = str_to_side(jsn.get('side', ''))
2020
remaining_volume = float(jsn.get('remaining_size', 'nan'))
2121
reason = jsn.get('reason', '')
2222
sequence = int(jsn.get('sequence'))
23-
2423
ret = MarketData(time=time,
2524
volume=volume,
2625
price=price,
2726
type=typ,
28-
currency=currency,
27+
currency_pair=currency_pair,
2928
remaining=remaining_volume,
3029
reason=reason,
3130
side=side,
@@ -55,7 +54,7 @@ def trade_req_to_params(req) -> dict:
5554
p = {}
5655
p['price'] = str(req.price)
5756
p['size'] = str(req.volume)
58-
p['product_id'] = GDAXHelpersMixin.currency_to_string(req.currency)
57+
p['product_id'] = GDAXHelpersMixin.currency_pair_to_string(req.currency_pair)
5958
p['type'] = GDAXHelpersMixin.order_type_to_string(req.order_type)
6059

6160
if req.order_sub_type == OrderSubType.FILL_OR_KILL:
@@ -67,7 +66,40 @@ def trade_req_to_params(req) -> dict:
6766
@staticmethod
6867
def currency_to_string(cur: CurrencyType) -> str:
6968
if cur == CurrencyType.BTC:
69+
return 'BTC'
70+
if cur == CurrencyType.ETH:
71+
return 'ETH'
72+
if cur == CurrencyType.LTC:
73+
return 'LTC'
74+
if cur == CurrencyType.BCH:
75+
return 'BCH'
76+
else:
77+
raise Exception('Pair not recognized: %s' % str(cur))
78+
79+
@staticmethod
80+
def currency_pair_to_string(cur: PairType) -> str:
81+
if cur == PairType.BTCUSD:
7082
return 'BTC-USD'
83+
if cur == PairType.BTCETH:
84+
return 'BTC-ETH'
85+
if cur == PairType.BTCLTC:
86+
return 'BTC-LTC'
87+
if cur == PairType.BTCBCH:
88+
return 'BTC-BCH'
89+
if cur == PairType.ETHUSD:
90+
return 'ETH-USD'
91+
if cur == PairType.LTCUSD:
92+
return 'LTC-USD'
93+
if cur == PairType.BCHUSD:
94+
return 'BCH-USD'
95+
if cur == PairType.ETHBTC:
96+
return 'ETH-BTC'
97+
if cur == PairType.LTCBTC:
98+
return 'LTC-BTC'
99+
if cur == PairType.BCHBTC:
100+
return 'BCH-BTC'
101+
else:
102+
raise Exception('Pair not recognized: %s' % str(cur))
71103

72104
@staticmethod
73105
def order_type_to_string(typ: OrderType) -> str:
@@ -96,13 +128,13 @@ def tickToData(jsn: dict) -> MarketData:
96128
remaining_volume = float(jsn.get('remaining', 'nan'))
97129

98130
sequence = -1
99-
currency = str_to_currency_type('BTC')
131+
currency_pair = str_to_currency_type('BTC')
100132

101133
ret = MarketData(time=time,
102134
volume=volume,
103135
price=price,
104136
type=typ,
105-
currency=currency,
137+
currency_pair=currency_pair,
106138
remaining=remaining_volume,
107139
reason=reason,
108140
side=side,
@@ -136,7 +168,7 @@ def trade_req_to_params(req) -> dict:
136168
p = {}
137169
p['price'] = str(req.price)
138170
p['size'] = str(req.volume)
139-
p['product_id'] = GeminiHelpersMixin.currency_to_string(req.currency)
171+
p['product_id'] = GeminiHelpersMixin.currency_pair_to_string(req.currency_pair)
140172
p['type'] = GeminiHelpersMixin.order_type_to_string(req.order_type)
141173

142174
if p['type'] == OrderType.MARKET:
@@ -152,9 +184,21 @@ def trade_req_to_params(req) -> dict:
152184
return p
153185

154186
@staticmethod
155-
def currency_to_string(cur: CurrencyType) -> str:
156-
if cur == CurrencyType.BTC:
187+
def currency_pair_to_string(cur: PairType) -> str:
188+
if cur == PairType.BTCUSD:
157189
return 'BTCUSD'
190+
if cur == PairType.ZECUSD:
191+
return 'ZECUSD'
192+
if cur == PairType.ZECBTC:
193+
return 'ZECBTC'
194+
if cur == PairType.ZECETH:
195+
return 'ZECETH'
196+
if cur == PairType.ETHBTC:
197+
return 'ETHBTC'
198+
if cur == PairType.ETHUSD:
199+
return 'ETHUSD'
200+
else:
201+
raise Exception('Pair not recognized: %s' % str(cur))
158202

159203
@staticmethod
160204
def order_type_to_string(typ: OrderType) -> str:

algocoin/lib/parser.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
from configparser import ConfigParser
22
from pydoc import locate
33
from .config import TradingEngineConfig, BacktestConfig, StrategyConfig
4-
from .enums import TradingType
4+
from .enums import TradingType, PairType
55
from .exceptions import ConfigException
6-
from .utils import str_to_exchange, exchange_to_file, set_verbose
6+
from .utils import str_to_exchange, exchange_to_file, set_verbose, str_to_currency_pair_type
77
from .logging import LOG as log
88

99

@@ -116,6 +116,14 @@ def _parse_args_to_dict(argv: list) -> dict:
116116
return ret
117117

118118

119+
def _parse_currencies(currencies):
120+
splits = [x.strip().upper().replace('-', '') for x in currencies.split(',')]
121+
ret = []
122+
for s in splits:
123+
ret.append(str_to_currency_pair_type(s))
124+
return ret
125+
126+
119127
def _parse_live_options(argv, config: TradingEngineConfig) -> None:
120128
log.critical("\n\nWARNING: Live trading. money will be lost ;^)\n\n")
121129
if argv.get('exchange'):
@@ -126,6 +134,9 @@ def _parse_live_options(argv, config: TradingEngineConfig) -> None:
126134
config.exchange_options.exchange_type = str_to_exchange('')
127135
log.critical('No Exchange set, using default: %s', config.exchange_options.exchange_type)
128136

137+
if argv.get('currency_pairs'):
138+
config.exchange_options.currency_pairs = _parse_currencies(argv.get('currency_pairs'))
139+
129140

130141
def _parse_sandbox_options(argv, config) -> None:
131142
log.critical("\n\nSandbox trading\n\n")
@@ -138,6 +149,9 @@ def _parse_sandbox_options(argv, config) -> None:
138149
config.exchange_options.exchange_type = str_to_exchange('')
139150
log.critical('No Exchange set, using default: %s', config.exchange_options.exchange_type)
140151

152+
if argv.get('currency_pairs'):
153+
config.exchange_options.currency_pairs = _parse_currencies(argv.get('currency_pairs'))
154+
141155

142156
def _parse_backtest_options(argv, config) -> None:
143157
log.critical("\n\nBacktesting\n\n")
@@ -152,6 +166,9 @@ def _parse_backtest_options(argv, config) -> None:
152166
config.exchange_options.exchange_type = str_to_exchange('')
153167
log.critical('No Exchange set, using default: %s', config.exchange_options.exchange_type)
154168

169+
if argv.get('currency_pairs'):
170+
config.exchange_options.currency_pairs = _parse_currencies(argv.get('currency_pairs'))
171+
155172

156173
def parse_command_line_config(argv: list) -> TradingEngineConfig:
157174
# Every engine run requires a static config object

algocoin/lib/strategies/backtest.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import numpy
2-
from .lib.strategy import TradingStrategy
3-
from .lib.structs import MarketData, TradeRequest, TradeResponse
4-
from .lib.enums import Side, OrderType
5-
from .lib.logging import STRAT as slog, ERROR as elog
2+
from ..strategy import TradingStrategy
3+
from ..structs import MarketData, TradeRequest, TradeResponse
4+
from ..enums import Side, OrderType
5+
from ..logging import STRAT as slog, ERROR as elog
66

77

88
class CustomStrategy(TradingStrategy):

algocoin/lib/strategies/sma_crosses_strategy.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ def onTrade(self, data: MarketData) -> bool:
9595
req = TradeRequest(side=Side.BUY,
9696
# buy between .2 and 1 BTC
9797
volume=max(min(1.0, data.volume), .2),
98-
currency=data.currency,
98+
currency_pair=data.currency_pair,
9999
order_type=OrderType.MARKET,
100100
price=data.price)
101101
# slog.info("requesting buy : %s", req)
@@ -106,7 +106,7 @@ def onTrade(self, data: MarketData) -> bool:
106106
self.bought > 0.0:
107107
req = TradeRequest(side=Side.SELL,
108108
volume=self.bought_qty,
109-
currency=data.currency,
109+
currency_pair=data.currency_pair,
110110
order_type=OrderType.MARKET,
111111
price=data.price)
112112
# slog.info("requesting sell : %s", req)

algocoin/lib/structs.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import datetime
22
from .enums import Side, \
33
CurrencyType, \
4+
PairType, \
45
OrderType, \
56
OrderSubType, \
67
TickType, \
@@ -15,7 +16,7 @@ class MarketData:
1516
volume = float
1617
price = float
1718
type = TickType
18-
currency = CurrencyType, CurrencyType.BTC
19+
currency_pair = PairType
1920
side = Side
2021

2122
# maybe specific
@@ -31,7 +32,7 @@ class TradeRequest:
3132

3233
volume = float
3334
price = float
34-
currency = CurrencyType
35+
currency_pair = PairType
3536

3637
order_type = OrderType
3738
order_sub_type = OrderSubType, OrderSubType.NONE
@@ -49,7 +50,7 @@ class TradeResponse:
4950

5051
volume = float
5152
price = float
52-
currency = CurrencyType
53+
currency_pair = PairType
5354

5455
slippage = float, 0.0
5556
transaction_cost = float, 0.0

0 commit comments

Comments
 (0)