-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCryptoTrader.py
More file actions
executable file
·199 lines (159 loc) · 9.63 KB
/
CryptoTrader.py
File metadata and controls
executable file
·199 lines (159 loc) · 9.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) Dave Beusing <david.beusing@gmail.com>
#
#
import asyncio
from decimal import Decimal, ROUND_DOWN
import numpy as np
import pandas as pd
import datetime as dt
from binance import Client, BinanceSocketManager
from sqlalchemy import create_engine
from config import Config
from utils import Credentials, IPC, queryDB, build_Frame, log
from models import Asset, Order, Trade
credentials = Credentials( 'key/binance.key' )
client = Client( credentials.key, credentials.secret )
client.timestamp_offset = -2000 #binance.exceptions.BinanceAPIException: APIError(code=-1021): Timestamp for this request was 1000ms ahead of the server's time.
engine = create_engine( f'sqlite:///{Config.Database}' )
### Start Bot place order
if not IPC.get( IPC.isRunning ):
# pull all symbols from DB
symbols = pd.read_sql( 'SELECT name FROM sqlite_master WHERE type = "table"', engine ).name.to_list()
# calculate cumulative return for each symbol
returns = []
for symbol in symbols:
prices = queryDB( engine, symbol, 2 ).Price #last 2 minutes
cumulative_return = ( prices.pct_change() + 1 ).prod() - 1
returns.append( { 'symbol' : symbol, 'cumret' : cumulative_return } )
# sort descending
sorted_returns = sorted(returns, key=lambda d: d['cumret'], reverse=True)
# prepare our Asset
asset = Asset( client, sorted_returns[0]['symbol'], OHLCV=True, Indicators=True )
# if the momentum already ends skip to next asset or wait a moment
if asset.OHLCV.ROC.iloc[-1] < Config.minROC:
print( f'{str(dt.datetime.now())} Opportunity not given, we skip this trade : {asset.symbol} (LvL0)' )
# check next Symbol
asset = Asset( client, sorted_returns[1]['symbol'], OHLCV=True, Indicators=True )
if asset.OHLCV.ROC.iloc[-1] < Config.minROC:
print( f'{str(dt.datetime.now())} Opportunity not given, we skip this trade : {asset.symbol} (LvL1)' )
# check next Symbol
asset = Asset( client, sorted_returns[2]['symbol'], OHLCV=True, Indicators=True )
if asset.OHLCV.ROC.iloc[-1] < Config.minROC:
print( f'{str(dt.datetime.now())} Opportunity not given, we skip this trade : {asset.symbol} (LvL2)' )
print( f'{str(dt.datetime.now())} No opportunities we give up and wait a moment...' )
quit()
### Momentum detected so place order
# check again if an instance is already running
if not IPC.get( IPC.isRunning ):
IPC.set( IPC.isRunning )
price = asset.getRecentPrice() # vielleicht sollten wir den letzten preis aus der DB nehmen? -> spart uns ein HTTP query + laufzeit
qty = asset.calculateQTY( Config.Investment, price=price )
order = Order( client, asset, Order.BUY, qty, price )
##TODO: implement logging
else:
### bot is already running
print( f'{str(dt.datetime.now())} Found an opportunity, but we are already invested.' )
quit()
else:
### bot is already running
print( f'{str(dt.datetime.now())} We are already invested.' )
quit()
#################################
### Monitor the current trade ###
#################################
async def main( asset, BuyOrder ):
bsm = BinanceSocketManager( client )
ts = bsm.trade_socket( asset.symbol )
print( f'{str(dt.datetime.now())} Start trading {asset.symbol}' )
async with ts as tscm:
while True:
response = await tscm.recv()
if response:
# build df from BSM response
frame = build_Frame( response )
CurrentPrice = frame.Price.iloc[-1]
TargetProfit = Decimal( BuyOrder.price ) + ( Decimal( BuyOrder.price ) * Decimal( Config.TargetProfit ) ) / 100
StopLoss = Decimal( BuyOrder.price ) + ( Decimal( BuyOrder.price ) * Decimal( -Config.StopLoss ) ) / 100
BreakEven = Decimal( BuyOrder.price ) + ( Decimal( BuyOrder.price ) * Decimal( Config.BreakEven ) ) / 100
# Trailing TakeProfit
if BuyOrder.TTP is not None:
TargetProfit = Decimal( BuyOrder.trail( 'get', 'TTP' ) )
StopLoss = Decimal( BuyOrder.trail( 'get', 'TSL' ) )
if CurrentPrice > TargetProfit:
TargetProfit = Decimal( CurrentPrice ) + ( Decimal( CurrentPrice ) * Decimal( .1 ) ) / 100
StopLoss = Decimal( TargetProfit ) + ( Decimal( TargetProfit ) * Decimal( -.1 ) ) / 100
BuyOrder.trail( 'set', 'TTP', TargetProfit )
BuyOrder.trail( 'set', 'TSL', StopLoss )
print( f'{str(dt.datetime.now())} TTP set TP:{TargetProfit} SL:{StopLoss}' )
#print( f'{str(dt.datetime.now())} {asset.symbol} BP:{BuyOrder.price:.4f} CP:{CurrentPrice} TP:{TargetProfit:.4f} SL:{StopLoss:.4f}' )
# benchmark for TSL!
if CurrentPrice < StopLoss or CurrentPrice > TargetProfit:
# This trade is closed, set Signal for a new one immediately
IPC.set( IPC.isRunning, remove=True )
# binance.exceptions.BinanceAPIException: APIError(code=-2010): Account has insufficient balance for requested action
# If we buy an asset we pay fee's with the bought asset, therefore we need to deduct the fee amount before we try to sell the position
# If we sell an asset the fee will be calculated (in our case) in USDT
SellQTY = Decimal( BuyOrder.qty - BuyOrder.commission ) # floor???
# binance.exceptions.BinanceAPIException: APIError(code=-1013): Filter failure: LOT_SIZE
#order = client.create_order( symbol=symbol, side='SELL', type='MARKET', quantity=sell_qty )
SellOrder = Order( client, asset, Order.SELL, SellQTY, CurrentPrice )
Dust = Decimal( BuyOrder.qty - SellOrder.qty )
ProfitPerShare = Decimal( SellOrder.price - BuyOrder.price ).quantize(Decimal('.00000001'), rounding=ROUND_DOWN)
ProfitTotal = Decimal( ProfitPerShare * SellOrder.qty ).quantize(Decimal('.00000001'), rounding=ROUND_DOWN)
ProfitRelative = Decimal( ( SellOrder.price - BuyOrder.price ) / BuyOrder.price ).quantize(Decimal('.00000001'), rounding=ROUND_DOWN)
Diff = round(( SellOrder.price - BuyOrder.price ) / BuyOrder.price *100, 2 )
#p = P / G
Duration = str( dt.datetime.now() - dt.datetime.fromtimestamp( BuyOrder.timestamp ) )
# create Trade Object
#FinalTrade = Trade()
# TODO: implement logging
state = None
if SellOrder.price > BuyOrder.price:
state = 'WON'
else:
state = 'LOST'
ds = { 'ts' : str(dt.datetime.now()), 'state' : state, 'symbol' : asset.symbol, 'duration' : str(Duration), 'ask' : str(BuyOrder.price), 'ask_qty' : str(BuyOrder.qty), 'bid' : str(SellOrder.price), 'bid_qty' : str(SellOrder.qty), 'profit' : str(ProfitPerShare), 'total_profit' : str(ProfitTotal), 'ROC' : asset.OHLCV.ROC.iloc[-1], 'RSI' : asset.OHLCV.RSI.iloc[-1], 'ATR' : asset.OHLCV.ATR.iloc[-1], 'OBV' : asset.OHLCV.OBV.iloc[-1] }
log( Config.Logfile, ds, timestamp=False )
print( f'###_Report_###' )
print( f'Symbol: {asset.symbol}' )
print( f'Condition: {state}' )
print( f'Investment: {Config.Investment} USDT' )
print( f'TP: {Config.TargetProfit}% SL: {Config.StopLoss}%')
print( f'Opened: {dt.datetime.fromtimestamp(BuyOrder.timestamp)}' )
print( f'Duration: {Duration}' )
print( f'Closed: {dt.datetime.fromtimestamp(SellOrder.timestamp)}' )
print( f'Ask: {BuyOrder.price} ({BuyOrder.qty})' )
print( f'Bid: {SellOrder.price} ({SellOrder.qty})' )
print( f'Dust: {Dust}' )
print( f'PPS: {ProfitPerShare}' )
print( f'Profit: {ProfitTotal}' )
print( f'Relative Profit: {ProfitRelative}' )
print( f'Diff: {Diff}' )
print( f'ROC: {asset.OHLCV.ROC.iloc[-1]}')
print( f'RSI: {asset.OHLCV.RSI.iloc[-1]}')
print( f'ATR: {asset.OHLCV.ATR.iloc[-1]}')
print( f'OBV: {asset.OHLCV.OBV.iloc[-1]}')
print( f'##############' )
#Stop & Exit the Loop
loop.stop()
# funktioniert ein break hier??
#RuntimeError: Event loop stopped before Future completed.
await client.close_connection()
if __name__ == "__main__":
loop = asyncio.get_event_loop()
'''
Traceback (most recent call last):
File "/home/dave/code/crypto/bot/CryptoPro.py", line 173, in <module>
loop.run_until_complete( main( asset, order ) )
File "/usr/lib/python3.9/asyncio/base_events.py", line 640, in run_until_complete
raise RuntimeError('Event loop stopped before Future completed.')
RuntimeError: Event loop stopped before Future completed.
'''
try:
loop.run_until_complete( main( asset, order ) )
except RuntimeError as e:
if e == 'Event loop stopped before Future completed.':
pass