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

Commit 68accdd

Browse files
committed
onExit 37, cleaned up some interfaces, exchange class makes more sense now
1 parent c70ba83 commit 68accdd

File tree

17 files changed

+224
-79
lines changed

17 files changed

+224
-79
lines changed

algocoin/execution.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,9 @@ def request(self, req: TradeRequest) -> TradeResponse:
2424
if req.side == Side.BUY:
2525
return self.requestBuy(req)
2626
return self.requestSell(req)
27+
28+
def cancel(self, resp: TradeResponse): # TODO
29+
return self._ex.cancel(resp)
30+
31+
def cancelAll(self):
32+
return self._ex.cancelAll()

algocoin/lib/callback.py

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,21 @@ def onChange(self, data: MarketData):
2929
def onError(self, data: MarketData):
3030
'''onError'''
3131

32-
def onAnalyze(self, data) -> None:
32+
def onExit(self):
33+
'''onExit'''
34+
pass
35+
36+
def onAnalyze(self, data):
3337
'''onAnalyze'''
34-
raise NotImplemented()
38+
pass
3539

36-
@abstractmethod
3740
def onHalt(self, data):
3841
'''onHalt'''
42+
pass
3943

40-
@abstractmethod
4144
def onContinue(self, data):
4245
'''onContinue'''
46+
pass
4347

4448
def callback(self):
4549
return self
@@ -67,15 +71,6 @@ def onChange(self, data: MarketData) -> None:
6771
def onError(self, data: MarketData) -> None:
6872
pass
6973

70-
def onAnalyze(self, data: MarketData) -> None:
71-
pass
72-
73-
def onHalt(self, data: MarketData) -> None:
74-
pass
75-
76-
def onContinue(self, data: MarketData) -> None:
77-
pass
78-
7974

8075
class Print(Callback):
8176
def __init__(self,

algocoin/lib/data_source.py

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,9 @@ def __init__(self, *args, **kwargs) -> None:
1313
pass
1414

1515
@abstractmethod
16-
def accountInfo(self):
16+
def accounts(self):
1717
'''get account information'''
1818

19-
@abstractmethod
20-
def sendOrder(self, callback: Callback):
21-
'''send order to exchange'''
22-
23-
@abstractmethod
24-
def orderResponse(self, response):
25-
'''parse the response'''
26-
2719
@abstractmethod
2820
def buy(self, req: TradeRequest) -> TradeResponse:
2921
'''execute a buy order'''
@@ -32,6 +24,18 @@ def buy(self, req: TradeRequest) -> TradeResponse:
3224
def sell(self, req: TradeRequest) -> TradeResponse:
3325
'''execute a sell order'''
3426

27+
@abstractmethod
28+
def cancel(self, resp: TradeResponse) -> None:
29+
'''cancel an order'''
30+
31+
@abstractmethod
32+
def cancelAll(self) -> None:
33+
'''cancel all orders'''
34+
35+
@abstractmethod
36+
def orderBook(self):
37+
'''return the order book'''
38+
3539

3640
class StreamingDataSource(DataSource):
3741
def __init__(self, *args, **kwargs) -> None:
@@ -91,6 +95,9 @@ def onChange(self, callback: Callback) -> None:
9195
def onError(self, callback: Callback) -> None:
9296
self._callbacks[TickType.ERROR].append(callback)
9397

98+
def onExit(self, callback: Callback) -> None:
99+
self._callbacks[TickType.EXIT].append(callback)
100+
94101
def onAnalyze(self, callback: Callback) -> None:
95102
self._callbacks[TickType.ANALYZE].append(callback)
96103

algocoin/lib/enums.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ class TickType(BaseEnum):
1717
ANALYZE = 6
1818
HALT = 7
1919
CONTINUE = 8
20-
HEARTBEAT = 9
20+
EXIT = 9
21+
HEARTBEAT = 10
2122

2223

2324
class TradingType(BaseEnum):

algocoin/lib/exchange.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import json
22
from .config import ExchangeConfig
3-
from .data_source import StreamingDataSource
3+
from .data_source import StreamingDataSource, RestAPIDataSource
44
from .logging import LOG as log
55
from .enums import TickType
66
from .define import EXCHANGE_MARKET_DATA_ENDPOINT, EXCHANGE_ORDER_ENDPOINT
77

88

9-
class Exchange(StreamingDataSource):
9+
class Exchange(StreamingDataSource, RestAPIDataSource):
1010
def __init__(self, options: ExchangeConfig) -> None:
1111
super(Exchange, self).__init__(options)
1212
self._lastseqnum = -1

algocoin/lib/exchanges/gdax.py

Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -90,26 +90,81 @@ def buy(self, req: TradeRequest) -> TradeResponse:
9090
'''execute a buy order'''
9191
params = GDAXExchange.trade_req_to_params(req)
9292
log.warn("Buy params: %s", str(params))
93-
res = self._client.buy(**params)
94-
return TradeResponse(request=req,
93+
order = self._client.buy(**params)
94+
'''{
95+
"id": "d0c5340b-6d6c-49d9-b567-48c4bfca13d2",
96+
"price": "0.10000000",
97+
"size": "0.01000000",
98+
"product_id": "BTC-USD",
99+
"side": "buy",
100+
"stp": "dc",
101+
"type": "limit",
102+
"time_in_force": "GTC",
103+
"post_only": false,
104+
"created_at": "2016-12-08T20:02:28.53864Z",
105+
"fill_fees": "0.0000000000000000",
106+
"filled_size": "0.00000000",
107+
"executed_value": "0.0000000000000000",
108+
"status": "pending",
109+
"settled": false
110+
}'''
111+
112+
# FIXME check these
113+
slippage = req.price-float(order['price'])
114+
txn_cost = float(order.get('fill_fees'))
115+
status = TradeResult.NONE
116+
117+
if (float(order['filled_size']) - req.volume) < 0.001 or order['status'] == 'done':
118+
status = TradeResult.FILLED
119+
elif False: # FIXME
120+
status = TradeResult.REJECTED
121+
elif float(order.get('filled_size', 0.0)) == req.size:
122+
status = TradeResult.PARTIAL
123+
else:
124+
status = TradeResult.PENDING
125+
126+
resp = TradeResponse(request=req,
95127
side=req.side,
96-
volume=0.0,
97-
price=0.0,
98-
currency=CurrencyType.BTC,
99-
slippage=0.0,
100-
transaction_cost=0.0,
101-
status=TradeResult.FILLED)
128+
volume=float(order['filled_size']),
129+
price=float(order['price']),
130+
currency=req.currency,
131+
slippage=slippage,
132+
transaction_cost=txn_cost,
133+
status=status,
134+
order_id=str(order['order_id']),
135+
remaining=float(order.get('remaining_amount', 0.0)),
136+
)
137+
return resp
102138

103139
def sell(self, req: TradeRequest) -> TradeResponse:
104140
'''execute a sell order'''
105141
params = GDAXExchange.trade_req_to_params(req)
106142
log.warn("Sell params: %s", str(params))
107-
res = self._client.sell(**params)
108-
return TradeResponse(request=req,
143+
order = self._client.sell(**params)
144+
145+
# FIXME check these
146+
slippage = req.price-float(order['price'])
147+
txn_cost = float(order.get('fill_fees'))
148+
status = TradeResult.NONE
149+
150+
if (float(order['filled_size']) - req.volume) < 0.001 or order['status'] == 'done':
151+
status = TradeResult.FILLED
152+
elif False: # FIXME
153+
status = TradeResult.REJECTED
154+
elif float(order.get('filled_size', 0.0)) == req.size:
155+
status = TradeResult.PARTIAL
156+
else:
157+
status = TradeResult.PENDING
158+
159+
resp = TradeResponse(request=req,
109160
side=req.side,
110-
volume=0.0,
111-
price=0.0,
112-
currency=CurrencyType.BTC,
113-
slippage=0.0,
114-
transaction_cost=0.0,
115-
status=TradeResult.FILLED)
161+
volume=float(order['filled_size']),
162+
price=float(order['price']),
163+
currency=req.currency,
164+
slippage=slippage,
165+
transaction_cost=txn_cost,
166+
status=status,
167+
order_id=str(order['order_id']),
168+
remaining=float(order.get('remaining_amount', 0.0)),
169+
)
170+
return resp

algocoin/lib/exchanges/gemini.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ def run(self, engine) -> None:
6767

6868
except KeyboardInterrupt:
6969
log.critical('Terminating program')
70+
engine.terminate()
7071
return
7172
return self._accounts
7273

@@ -84,7 +85,31 @@ def buy(self, req: TradeRequest) -> TradeResponse:
8485
'buy',
8586
client_order_id=None,
8687
order_execution=None)
88+
89+
'''{
90+
"avg_execution_price": "0.00",
91+
"client_order_id": "20170208_example",
92+
"exchange": "gemini",
93+
"executed_amount": "0",
94+
"id": "372456298",
95+
"is_cancelled": false,
96+
"is_hidden": false,
97+
"is_live": true,
98+
"order_id": "372456298",
99+
"original_amount": "14.0296",
100+
"price": "1059.54",
101+
"remaining_amount": "14.0296",
102+
"side": "buy",
103+
"symbol": "btcusd",
104+
"timestamp": "1478203017",
105+
"timestampms": 1478203017455,
106+
"type": "exchange limit",
107+
"was_forced": false
108+
}'''
87109
# FIXME check these
110+
if order.get('result') == 'error':
111+
raise Exception('Order Error!')
112+
88113
slippage = float(params['price'])-float(order['avg_execution_price'])
89114
txn_cost = 0.0
90115
status = TradeResult.NONE
@@ -122,8 +147,13 @@ def sell(self, req: TradeRequest) -> TradeResponse:
122147
client_order_id=None,
123148
order_execution=None)
124149

150+
if order.get('result') == 'error':
151+
raise Exception('Order Error!')
152+
125153
# FIXME check these
126-
slippage = float(params['price'])-float(order['avg_execution_price'])
154+
if 'avg_execution_price' not in order:
155+
import pdb; pdb.set_trace()
156+
slippage = float(params['price'])-float(order.get('avg_execution_price'))
127157
txn_cost = 0.0
128158
status = TradeResult.NONE
129159

@@ -176,3 +206,12 @@ def receive(self) -> None:
176206
pass
177207
else:
178208
self.callback(TickType.ERROR, res)
209+
210+
def cancel(self, resp: TradeResponse):
211+
'''cancel an order'''
212+
raise NotImplementedError()
213+
214+
def cancelAll(self) -> None:
215+
'''cancel all orders'''
216+
log.critical('Cancelling all active orders')
217+
self._client.cancel_all_active_orders()

algocoin/lib/order_book.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from abc import ABCMeta
2+
3+
4+
class OrderBook(metaclass=ABCMeta):
5+
'''OrderBook interface'''
6+
pass

algocoin/lib/strategies/test_strat.py

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,37 +48,35 @@ def onTrade(self, data: MarketData) -> bool:
4848
price=data.price)
4949
slog.critical("requesting buy : %s", req)
5050
self.requestBuy(self.onBuy, req)
51+
self.active = True
5152
return True
5253
else:
53-
req = TradeRequest(side=Side.SELL,
54-
volume=self.bought_qty,
55-
currency=data.currency,
56-
order_type=OrderType.MARKET,
57-
price=data.price)
58-
slog.critical("requesting sell : %s", req)
59-
self.requestSell(self.onSell, req)
60-
return True
61-
54+
if self.bought_qty:
55+
req = TradeRequest(side=Side.SELL,
56+
volume=self.bought_qty,
57+
currency=data.currency,
58+
order_type=OrderType.MARKET,
59+
price=data.price)
60+
slog.critical("requesting sell : %s", req)
61+
self.requestSell(self.onSell, req)
62+
self.active = False
63+
return True
64+
else:
65+
slog.critical('None bought yet!')
6266
return False
6367

6468
def onError(self, e) -> None:
6569
elog.critical(e)
6670

67-
def onAnalyze(self, _) -> None:
68-
pass
71+
def onExit(self) -> None:
72+
self.cancelAll(lambda *args: True)
6973

7074
def onChange(self, data: MarketData) -> None:
7175
pass
7276

73-
def onContinue(self, data: MarketData) -> None:
74-
pass
75-
7677
def onDone(self, data: MarketData) -> None:
7778
pass
7879

79-
def onHalt(self, data: MarketData) -> None:
80-
pass
81-
8280
def onOpen(self, data: MarketData) -> None:
8381
pass
8482

algocoin/lib/strategy.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,22 @@ def registerDesire(self, time, actionType, data) -> None:
4848

4949

5050
class TradingStrategy(Strategy, Callback):
51-
def requestBuy(self,
52-
callback: Callable,
53-
req: TradeRequest,
54-
callback_failure=None) -> None:
51+
def requestBuy(self, callback: Callable, req: TradeRequest, callback_failure=None) -> None:
52+
'''attempt to buy'''
5553
self._te.requestBuy(callback, req, callback_failure, self)
5654

57-
def requestSell(self,
58-
callback: Callable,
59-
req: TradeRequest,
60-
callback_failure=None) -> None:
55+
def requestSell(self, callback: Callable, req: TradeRequest, callback_failure=None) -> None:
56+
'''attempt to sell'''
6157
self._te.requestSell(callback, req, callback_failure, self)
6258

59+
def cancel(self, callback: Callable, resp: TradeResponse, callback_failure=None) -> None:
60+
'''cancel order'''
61+
self._te.cancel(callback, resp, callback_failure, self)
62+
63+
def cancelAll(self, callback: Callable, callback_failure=None):
64+
'''cancel all orders'''
65+
self._te.cancelAll(callback, callback_failure, self)
66+
6367
def slippage(self, data: TradeResponse) -> TradeResponse:
6468
'''slippage model. default is pass through'''
6569
return data

0 commit comments

Comments
 (0)