draft nove classis strategie

This commit is contained in:
David Brazda
2023-08-24 21:12:45 +02:00
parent 2c7d279303
commit 88bd8c30c2
27 changed files with 1395 additions and 47 deletions

14
alpacawebsokcet.py Normal file
View File

@ -0,0 +1,14 @@
from alpaca.data.live.stock import StockDataStream
from v2realbot.config import ACCOUNT2_PAPER_API_KEY, ACCOUNT2_PAPER_SECRET_KEY, ACCOUNT2_PAPER_FEED
# keys required
stock_stream = StockDataStream(ACCOUNT2_PAPER_API_KEY, ACCOUNT2_PAPER_SECRET_KEY, raw_data=True, websocket_params={}, feed=ACCOUNT2_PAPER_FEED)
# async handler
async def trade_data_handler(data):
# quote data will arrive here
print(data)
stock_stream.subscribe_trades(trade_data_handler, "BAC")
stock_stream.run()

View File

@ -4,7 +4,7 @@ from alpaca.trading.stream import TradingStream
from alpaca.data.enums import DataFeed from alpaca.data.enums import DataFeed
from config import API_KEY, SECRET_KEY, MAX_BATCH_SIZE from config import API_KEY, SECRET_KEY, MAX_BATCH_SIZE
from datetime import datetime from datetime import datetime
import mplfinance as mpf #import mplfinance as mpf
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import threading import threading
# pripadne parametry pro request # pripadne parametry pro request

View File

@ -1039,6 +1039,9 @@ res = dict(zip(max_positions['qty'], max_positions['count']))
ouput_dict=dict(maxpos=str(res)) ouput_dict=dict(maxpos=str(res))
all_summary = trade_df.describe(include='all')
print(all_summary)
print(ouput_dict) print(ouput_dict)
#a = trade_df.value_counts(subset=['position_qty']) #a = trade_df.value_counts(subset=['position_qty'])
#print(max_positions.to_dict('records')) #print(max_positions.to_dict('records'))

View File

@ -1,7 +1,7 @@
from threading import Thread, current_thread from threading import Thread, current_thread
import threading import threading
from alpaca.data.live import StockDataStream, CryptoDataStream from alpaca.data.live import StockDataStream, CryptoDataStream
from v2realbot.config import API_KEY, SECRET_KEY, MAX_BATCH_SIZE, PAPER from v2realbot.config import ACCOUNT1_PAPER_API_KEY, ACCOUNT1_PAPER_SECRET_KEY, ACCOUNT1_PAPER_MAX_BATCH_SIZE
import queue import queue
from alpaca.data.enums import DataFeed from alpaca.data.enums import DataFeed
from typing_extensions import Any from typing_extensions import Any
@ -27,7 +27,7 @@ vlakno je vzdy pouze jedno, nicmene instancovani teto tridy je kvuli stejnemu ch
s ostatnimi streamery (v budoucnu mozna predelat na dedicated streamer a shared streamer) s ostatnimi streamery (v budoucnu mozna predelat na dedicated streamer a shared streamer)
""""" """""
class WS_Stream(Thread): class WS_Stream(Thread):
client = CryptoDataStream(API_KEY, SECRET_KEY, raw_data=True, websocket_params={}) client = CryptoDataStream(ACCOUNT1_PAPER_API_KEY, ACCOUNT1_PAPER_SECRET_KEY, raw_data=True, websocket_params={})
_streams = [] _streams = []
lock = threading.Lock() lock = threading.Lock()
@ -124,12 +124,12 @@ class WS_Stream(Thread):
# novy ws stream - vždy jednom vláknu # novy ws stream - vždy jednom vláknu
obj= WS_Stream(name="jednicka") obj= WS_Stream(name="jednicka")
q1 = queue.Queue() q1 = queue.Queue()
stream1 = TradeAggregator2Queue(symbol="BTC/USD",queue=q1,rectype=RecordType.BAR,timeframe=15,update_ltp=False,align=StartBarAlign.ROUND,mintick = 0, mode = Mode.LIVE) stream1 = TradeAggregator2Queue(symbol="BTC/USD",queue=q1,rectype=RecordType.BAR,timeframe=1,update_ltp=False,align=StartBarAlign.ROUND,mintick = 0)
obj.add_stream(stream1) obj.add_stream(stream1)
print("1", WS_Stream._streams) print("1", WS_Stream._streams)
# novy ws stream - vždy jednom vláknu # novy ws stream - vždy jednom vláknu
obj2= WS_Stream("dvojka") obj2= WS_Stream("dvojka")
stream2 = TradeAggregator2Queue(symbol="ETH/USD",queue=q1,rectype=RecordType.BAR,timeframe=5,update_ltp=False,align=StartBarAlign.ROUND,mintick = 0, mode = Mode.LIVE) stream2 = TradeAggregator2Queue(symbol="ETH/USD",queue=q1,rectype=RecordType.BAR,timeframe=1,update_ltp=False,align=StartBarAlign.ROUND,mintick = 0)
obj2.add_stream(stream2) obj2.add_stream(stream2)
print("2", WS_Stream._streams) print("2", WS_Stream._streams)
obj.start() obj.start()
@ -141,7 +141,7 @@ print("po startu druheho")
time.sleep(2) time.sleep(2)
print("pridavame treti") print("pridavame treti")
obj3 = WS_Stream(name="trojka") obj3 = WS_Stream(name="trojka")
stream3 = TradeAggregator2Queue(symbol="BTC/USD",queue=q1,rectype=RecordType.BAR,timeframe=1,update_ltp=False,align=StartBarAlign.ROUND,mintick = 0, mode = Mode.LIVE) stream3 = TradeAggregator2Queue(symbol="BTC/USD",queue=q1,rectype=RecordType.BAR,timeframe=1,update_ltp=False,align=StartBarAlign.ROUND,mintick = 0)
obj3.add_stream(stream3) obj3.add_stream(stream3)
obj3.start() obj3.start()
print(WS_Stream._streams) print(WS_Stream._streams)

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@ from v2realbot.strategy.StrategyOrderLimitVykladaciNormalizedMYSELL import Strat
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide, OrderType from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide, OrderType
from v2realbot.indicators.indicators import ema from v2realbot.indicators.indicators import ema
from v2realbot.indicators.oscillators import rsi from v2realbot.indicators.oscillators import rsi
from v2realbot.utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY, price2dec, print, safe_get, get_tick, round2five, is_open_rush, is_close_rush, eval_cond_dict, Average, crossed_down, crossed_up, is_pivot from v2realbot.utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY, price2dec, print, safe_get, get_tick, round2five, is_open_rush, is_close_rush, eval_cond_dict, Average, crossed_down, crossed_up, crossed, is_pivot
from datetime import datetime from datetime import datetime
#from icecream import install, ic #from icecream import install, ic
#from rich import print #from rich import print
@ -536,6 +536,7 @@ def next(data, state: StrategyState):
#u indikatoru muzoun byt tyto directivy pro generovani buysignalu #u indikatoru muzoun byt tyto directivy pro generovani buysignalu
# buy_if_crossed_down - kdyz prekrocil dolu, VALUE: hodnota nebo nazev indikatoru # buy_if_crossed_down - kdyz prekrocil dolu, VALUE: hodnota nebo nazev indikatoru
# buy_if_crossed_up - kdyz prekrocil nahoru, VALUE: hodnota nebo nazev indikatoru # buy_if_crossed_up - kdyz prekrocil nahoru, VALUE: hodnota nebo nazev indikatoru
# buy_if_crossed - kdyz krosne obema smery, VALUE: hodnota nebo nazev indikatoru
# buy_if_falling - kdyz je klesajici po N, VALUE: hodnota # buy_if_falling - kdyz je klesajici po N, VALUE: hodnota
# buy_if_rising - kdyz je rostouci po N, VALUE: hodnota # buy_if_rising - kdyz je rostouci po N, VALUE: hodnota
# buy_if_below - kdyz je pod prahem, VALUE: hodnota nebo nazev indikatoru # buy_if_below - kdyz je pod prahem, VALUE: hodnota nebo nazev indikatoru
@ -607,6 +608,9 @@ def next(data, state: StrategyState):
cond[cond_type][directive+"_"+indname+"_"+str(value)] = buy_if_crossed_down(indname, value_or_indicator(value)) cond[cond_type][directive+"_"+indname+"_"+str(value)] = buy_if_crossed_down(indname, value_or_indicator(value))
elif directive.endswith("crossed_up"): elif directive.endswith("crossed_up"):
cond[cond_type][directive+"_"+indname+"_"+str(value)] = buy_if_crossed_up(indname, value_or_indicator(value)) cond[cond_type][directive+"_"+indname+"_"+str(value)] = buy_if_crossed_up(indname, value_or_indicator(value))
#nefunguje moc dobre
elif directive.endswith("crossed"):
cond[cond_type][directive+"_"+indname+"_"+str(value)] = buy_if_crossed_down(indname, value_or_indicator(value)) or buy_if_crossed_up(indname, value_or_indicator(value))
elif directive.endswith("pivot_a"): elif directive.endswith("pivot_a"):
cond[cond_type][directive+"_"+indname+"_"+str(value)] = is_pivot(source=get_source_or_MA(indname), leg_number=value, type="A") cond[cond_type][directive+"_"+indname+"_"+str(value)] = is_pivot(source=get_source_or_MA(indname), leg_number=value, type="A")
elif directive.endswith("pivot_v"): elif directive.endswith("pivot_v"):
@ -618,7 +622,6 @@ def next(data, state: StrategyState):
return cond return cond
#tato funkce vytvori dictionary typu podminek (OR/AND) #tato funkce vytvori dictionary typu podminek (OR/AND)
# z indikatoru, ktere obsahuji direktivami daneho typu(buy_if, dont_buy_when) # z indikatoru, ktere obsahuji direktivami daneho typu(buy_if, dont_buy_when)
# v tuplu (nazevind,direktiva,hodnota) # v tuplu (nazevind,direktiva,hodnota)
@ -650,6 +653,12 @@ def next(data, state: StrategyState):
except KeyError: except KeyError:
return state.indicators[indicator] return state.indicators[indicator]
# #vrati true pokud dany indikator krosnul obema smery
# def buy_if_crossed(indicator, value):
# res = crossed(threshold=value, list=get_source_or_MA(indicator))
# state.ilog(e=f"buy_if_crossed {indicator} {value} {res}")
# return res
#vrati true pokud dany indikator prekrocil threshold dolu #vrati true pokud dany indikator prekrocil threshold dolu
def buy_if_crossed_down(indicator, value): def buy_if_crossed_down(indicator, value):
res = crossed_down(threshold=value, list=get_source_or_MA(indicator)) res = crossed_down(threshold=value, list=get_source_or_MA(indicator))
@ -820,6 +829,10 @@ def next(data, state: StrategyState):
#poustet kazdy tick nebo jenom na confirmed baru (on_confirmed_only = true) #poustet kazdy tick nebo jenom na confirmed baru (on_confirmed_only = true)
on_confirmed_only = safe_get(options, 'on_confirmed_only', False) on_confirmed_only = safe_get(options, 'on_confirmed_only', False)
#pocet baru po kterých se levy bod z BUY prepne opet na standadni vypocet (prumer)
#kdyz se dlouho neprodává a cena nejde dolu, tak aby se nezastavilo nakupovani
back_to_standard_after = int(safe_get(options, 'back_to_standard_after', 0))
#slopeLP INDIKATOR #slopeLP INDIKATOR
#levy bod je nejdrive standardne automaticky vypočtený podle hodnoty lookbacku (např. -8, offset 4) #levy bod je nejdrive standardne automaticky vypočtený podle hodnoty lookbacku (např. -8, offset 4)
#při nákupu se BUY POINT se stává levým bodem (až do doby kdy není lookbackprice nižší, pak pokračuje lookbackprice) #při nákupu se BUY POINT se stává levým bodem (až do doby kdy není lookbackprice nižší, pak pokračuje lookbackprice)
@ -862,10 +875,11 @@ def next(data, state: StrategyState):
lookbacktime = state.bars.time[-slope_lookback] lookbacktime = state.bars.time[-slope_lookback]
#pokud mame aktivni pozice, nastavime lookbackprice a time podle posledniho tradu #pokud mame aktivni pozice, nastavime lookbackprice a time podle posledniho tradu
if state.avgp > 0: #pokud se ale dlouho nenakupuje (uplynulo od posledniho nakupu vic nez back_to_standard_after baru), tak se vracime k prumeru
if state.avgp > 0 and state.bars.index[-1] < int(state.vars.lastbuyindex)+back_to_standard_after:
lb_index = -1 - (state.bars.index[-1] - int(state.vars.lastbuyindex)) lb_index = -1 - (state.bars.index[-1] - int(state.vars.lastbuyindex))
lookbackprice = state.bars.vwap[lb_index] lookbackprice = state.bars.vwap[lb_index]
state.ilog(e=f"IND {name} slope {leftpoint}- LEFT POINT OVERRIDE bereme buy {state.avgp=} {lookbackprice=} {lookbacktime=} {lb_index=}") state.ilog(e=f"IND {name} slope {leftpoint}- LEFT POINT OVERRIDE bereme ajko cenu lastbuy {lookbackprice=} {lookbacktime=} {lb_index=}")
else: else:
#dame na porovnani jen prumer #dame na porovnani jen prumer
lookbackprice = round(sum(lookbackprice_array)/lookback_offset,3) lookbackprice = round(sum(lookbackprice_array)/lookback_offset,3)
@ -879,7 +893,7 @@ def next(data, state: StrategyState):
# lookbackprice = round(sum(lookbackprice_array)/lookback_offset,3) # lookbackprice = round(sum(lookbackprice_array)/lookback_offset,3)
lookbacktime = state.bars.time[-slope_lookback] lookbacktime = state.bars.time[-slope_lookback]
state.ilog(e=f"IND {name} slope {leftpoint} - LEFT POINT STANDARD AVGP {state.avgp} {lookbackprice=} {lookbacktime=}") state.ilog(e=f"IND {name} slope {leftpoint} - LEFT POINT STANDARD {lookbackprice=} {lookbacktime=}")
else: else:
#kdyz neni dostatek hodnot, pouzivame jako levy bod open hodnotu close[0] #kdyz neni dostatek hodnot, pouzivame jako levy bod open hodnotu close[0]
lookbackprice = state.bars.close[0] lookbackprice = state.bars.close[0]

View File

@ -87,6 +87,7 @@ class Backtester:
self.bp_from = bp_from self.bp_from = bp_from
self.bp_to = bp_to self.bp_to = bp_to
self.cash = cash self.cash = cash
self.cash_reserved_for_shorting = 0
self.trades = [] self.trades = []
self.account = { "BAC": [0, 0] } self.account = { "BAC": [0, 0] }
# { "BAC": [avgp, size] } # { "BAC": [avgp, size] }
@ -372,23 +373,43 @@ class Backtester:
if o.side == OrderSide.BUY: if o.side == OrderSide.BUY:
#[size, avgp] #[size, avgp]
if (self.account[o.symbol][0] + o.qty) == 0: newavgp = 0 newsize = (self.account[o.symbol][0] + o.qty)
#JPLNE UZAVRENI SHORT (avgp 0)
if newsize == 0: newavgp = 0
#CASTECNE UZAVRENI SHORT (avgp puvodni)
elif newsize < 0: newavgp = self.account[o.symbol][1]
#JDE O LONG (avgp nove)
else: else:
newavgp = ((self.account[o.symbol][0] * self.account[o.symbol][1]) + (o.qty * o.filled_avg_price)) / (self.account[o.symbol][0] + o.qty) newavgp = ((self.account[o.symbol][0] * self.account[o.symbol][1]) + (o.qty * o.filled_avg_price)) / (self.account[o.symbol][0] + o.qty)
self.account[o.symbol] = [self.account[o.symbol][0]+o.qty, newavgp]
self.account[o.symbol] = [newsize, newavgp]
self.cash = self.cash - (o.qty * o.filled_avg_price) self.cash = self.cash - (o.qty * o.filled_avg_price)
return 1 return 1
#sell #sell
elif o.side == OrderSide.SELL: elif o.side == OrderSide.SELL:
newsize = self.account[o.symbol][0]-o.qty newsize = self.account[o.symbol][0]-o.qty
#UPLNE UZAVRENI LONGU (avgp 0)
if newsize == 0: newavgp = 0 if newsize == 0: newavgp = 0
#CASTECNE UZAVRENI LONGU (avgp puvodni)
elif newsize > 0: newavgp = self.account[o.symbol][1]
#jde o SHORT (avgp nove)
else: else:
#pokud je predchozi 0 - tzn. jde o prvni short
if self.account[o.symbol][1] == 0: if self.account[o.symbol][1] == 0:
newavgp = o.filled_avg_price newavgp = o.filled_avg_price
else: else:
newavgp = self.account[o.symbol][1] newavgp = ((abs(self.account[o.symbol][0]) * self.account[o.symbol][1]) + (o.qty * o.filled_avg_price)) / (abs(self.account[o.symbol][0]) + o.qty)
self.account[o.symbol] = [newsize, newavgp] self.account[o.symbol] = [newsize, newavgp]
self.cash = float(self.cash + (o.qty * o.filled_avg_price))
#pokud jde o prodej longu(nova pozice je>=0) upravujeme cash
if self.account[o.symbol][0] >= 0:
self.cash = float(self.cash + (o.qty * o.filled_avg_price))
print("uprava cashe, jde o prodej longu")
else:
self.cash = float(self.cash + (o.qty * o.filled_avg_price))
#self.cash_reserved_for_shorting += float(o.qty * o.filled_avg_price)
print("jde o short, upravujeme cash zatim stejne")
return 1 return 1
else: else:
print("neznaama side", o.side) print("neznaama side", o.side)
@ -467,31 +488,53 @@ class Backtester:
#check for available quantity #check for available quantity
if side == OrderSide.SELL: if side == OrderSide.SELL:
reserved = 0 reserved = 0
reserved_price = 0
#with lock: #with lock:
for o in self.open_orders: for o in self.open_orders:
if o.side == OrderSide.SELL and o.symbol == symbol and o.canceled_at is None: if o.side == OrderSide.SELL and o.symbol == symbol and o.canceled_at is None:
reserved += o.qty reserved += o.qty
print("blokovano v open orders pro sell: ", reserved) cena = o.limit_price if o.limit_price else self.get_last_price(time, o.symbol)
reserved_price += o.qty * cena
print("blokovano v open orders pro sell qty: ", reserved, "celkem:", reserved_price)
if int(self.account[symbol][0]) - reserved - int(size) < 0: actual_minus_reserved = int(self.account[symbol][0]) - reserved
print("not enough shares having",self.account[symbol][0],"reserved",reserved,"available",int(self.account[symbol][0]) - reserved,"selling",size) if actual_minus_reserved > 0 and actual_minus_reserved - int(size) < 0:
print("not enough shares available to sell or shorting while long position",self.account[symbol][0],"reserved",reserved,"available",int(self.account[symbol][0]) - reserved,"selling",size)
return -1 return -1
#if is shorting - check available cash to short
if actual_minus_reserved <= 0:
cena = price if price else self.get_last_price(time, self.symbol)
if (self.cash - reserved_price - float(int(size)*float(cena))) < 0:
print("not enough cash for shorting. cash",self.cash,"reserved",reserved,"available",self.cash-reserved,"needed",float(int(size)*float(cena)))
return -1
#check for available cash #check for available cash
if side == OrderSide.BUY: if side == OrderSide.BUY:
reserved = 0 reserved_qty = 0
reserved_price = 0
#with lock: #with lock:
for o in self.open_orders: for o in self.open_orders:
if o.side == OrderSide.BUY and o.canceled_at is None: if o.side == OrderSide.BUY and o.canceled_at is None:
cena = o.limit_price if o.limit_price else self.get_last_price(time, o.symbol) cena = o.limit_price if o.limit_price else self.get_last_price(time, o.symbol)
reserved += o.qty * cena reserved_price += o.qty * cena
print("blokovano v open orders: ", reserved) reserved_qty += o.qty
print("blokovano v open orders for buy: qty, price", reserved_qty, reserved_price)
cena = price if price else self.get_last_price(time, self.symbol) actual_plus_reserved_qty = int(self.account[symbol][0]) + reserved_qty
if (self.cash - reserved - float(int(size)*float(cena))) < 0:
print("not enough cash. cash",self.cash,"reserved",reserved,"available",self.cash-reserved,"needed",float(int(size)*float(cena))) #jde o uzavreni shortu
if actual_plus_reserved_qty < 0 and (actual_plus_reserved_qty + int(size)) > 0:
print("nejprve je treba uzavrit short pozici pro buy res_qty, size", actual_plus_reserved_qty, size)
return -1 return -1
#jde o standardni long, kontroluju cash
if actual_plus_reserved_qty >= 0:
cena = price if price else self.get_last_price(time, self.symbol)
if (self.cash - reserved_price - float(int(size)*float(cena))) < 0:
print("not enough cash to buy long. cash",self.cash,"reserved_qty",reserved_qty,"reserved_price",reserved_price, "available",self.cash-reserved_price,"needed",float(int(size)*float(cena)))
return -1
id = str(uuid4()) id = str(uuid4())
order = Order(id=id, order = Order(id=id,
submitted_at = datetime.fromtimestamp(float(time)), submitted_at = datetime.fromtimestamp(float(time)),

View File

@ -0,0 +1,27 @@
from enum import Enum
from datetime import datetime
from pydantic import BaseModel
from typing import Any, Optional, List, Union
class TradeStatus(str, Enum):
READY = "ready"
ACTIVATED = "activated"
#FINISHED = "finished"
class TradeDirection(str, Enum):
LONG = "long"
SHORT = "short"
class TradeStoplossType(str, Enum):
FIXED = "fixed"
TRAILING = "trailing"
class Trade(BaseModel):
validfrom: datetime
status: TradeStatus
direction: TradeDirection
entry_price: Optional[float] = None
# stoploss_type: TradeStoplossType
stoploss_value: Optional[float] = None
profit: Optional[float] = None

View File

@ -18,13 +18,12 @@ from alpaca.data.enums import Exchange
# if user_update.first_name is not None: # if user_update.first_name is not None:
# user.first_name = user_update.first_name # user.first_name = user_update.first_name
# if user_update.last_name is not None: # if user_update.last_name is not None:
# user.last_name = user_update.last_name # userbase.last_name = user_update.last_name
# if user_update.roles is not None: # if user_update.roles is not None:
# user.roles = user_update.roles # user.roles = user_update.roles
# return user.id # return user.id
# raise HTTPException(status_code=404, detail=f"Could not find user with id: {id}") # raise HTTPException(status_code=404, detail=f"Could not find user with id: {id}")
class Intervals(BaseModel): class Intervals(BaseModel):
start: str start: str
end: str end: str

View File

@ -92,8 +92,8 @@ ACCOUNT1_LIVE_PAPER = False
ACCOUNT1_LIVE_FEED = DataFeed.SIP ACCOUNT1_LIVE_FEED = DataFeed.SIP
#SECONDARY PAPER #SECONDARY PAPER
ACCOUNT2_PAPER_API_KEY = 'PKQEAAJTVC72SZO3CT3R' ACCOUNT2_PAPER_API_KEY = 'PK0OQHZG03PUZ1SC560V'
ACCOUNT2_PAPER_SECRET_KEY = 'mqdftzGJlJdvUjdsuQynAURCHRwAI0a8nhJy8nyz' ACCOUNT2_PAPER_SECRET_KEY = 'cTglhm7kwRcZfFT27fQWz31sXaxadzQApFDW6Lat'
ACCOUNT2_PAPER_MAX_BATCH_SIZE = 1 ACCOUNT2_PAPER_MAX_BATCH_SIZE = 1
ACCOUNT2_PAPER_PAPER = True ACCOUNT2_PAPER_PAPER = True
ACCOUNT2_PAPER_FEED = DataFeed.IEX ACCOUNT2_PAPER_FEED = DataFeed.IEX

View File

@ -11,7 +11,7 @@ import threading
from copy import deepcopy from copy import deepcopy
from msgpack import unpackb from msgpack import unpackb
import os import os
from config import DATA_DIR, GROUP_TRADES_WITH_TIMESTAMP_LESS_THAN from v2realbot.config import DATA_DIR, GROUP_TRADES_WITH_TIMESTAMP_LESS_THAN
class TradeAggregator: class TradeAggregator:
def __init__(self, def __init__(self,
@ -383,7 +383,7 @@ class TradeAggregator2Queue(TradeAggregator):
copy = obj copy = obj
##populate secondary resolution if required ##populate secondary resolution if required
#print("inserted to queue")
self.queue.put(copy) self.queue.put(copy)
res = [] res = []
#print("po insertu",res) #print("po insertu",res)

View File

@ -42,17 +42,19 @@ class Trade_Offline_Streamer(Thread):
pass pass
def run(self): def run(self):
#create new asyncio loop in the thread self.main()
loop = asyncio.new_event_loop() # #create new asyncio loop in the thread
asyncio.set_event_loop(loop) # loop = asyncio.new_event_loop()
loop.create_task(self.main()) # asyncio.set_event_loop(loop)
loop.run_forever() # loop.create_task(self.main())
# loop.run_forever()
def stop(self): def stop(self):
pass pass
# Override the run() function of Thread class # Override the run() function of Thread class
async def main(self): #odebrano async
def main(self):
print(10*"*","Trade OFFLINE streamer STARTED", current_thread().name,10*"*") print(10*"*","Trade OFFLINE streamer STARTED", current_thread().name,10*"*")
if not self.streams: if not self.streams:
@ -194,16 +196,24 @@ class Trade_Offline_Streamer(Thread):
for s in self.to_run[symbol]: for s in self.to_run[symbol]:
#print("zaznam",t) #print("zaznam",t)
#print("Ingest", s, "zaznam", t) #print("Ingest", s, "zaznam", t)
await s.ingest_trade(packb(t)) #await s.ingest_trade(packb(t))
asyncio.run(s.ingest_trade(packb(t)))
cnt += 1 cnt += 1
#protoze jsou serazene, tak prvni ktery je vetsi muze prerusit
elif to_datetime(t['t']) > self.time_to:
print("prerusujeme")
break
#vsem streamum posleme last TODO: (tuto celou cast prepsat a zjednodusit) #vsem streamum posleme last TODO: (tuto celou cast prepsat a zjednodusit)
#po loadovani vsech dnu #po loadovani vsech dnu
print("naloadovane vse posilame last")
for s in self.to_run[symbpole[0]]: for s in self.to_run[symbpole[0]]:
await s.ingest_trade(packb("last")) #zde bylo await
asyncio.run(s.ingest_trade(packb("last")))
print("poslano last")
loop = asyncio.get_running_loop() #loop = asyncio.get_running_loop()
print("stoping loop") print("stoping loop")
loop.stop() #loop.stop()
print(10*"*","Trade OFFLINE streamer STOPPED", current_thread().name,10*"*") print(10*"*","Trade OFFLINE streamer STOPPED", current_thread().name,10*"*")

View File

@ -72,10 +72,11 @@ function transform_data(data) {
last_timestamp = timestamp last_timestamp = timestamp
iterator = 0.002 iterator = 0.002
} }
//puvodne bylo pro buy
if (trade.order.side == "buy") { //pro sell muzeme teoreticky taky mit buyline (pri shortu)
if ((trade.order.side == "buy") || (trade.order.side == "sell")) {
//avgp lajnu vytvarime jen pokud je v tradeventu prumerna cena //avgp lajnu vytvarime jen pokud je v tradeventu prumerna cena
if (trade.pos_avg_price !== null) { if ((trade.pos_avg_price !== null) && (trade.pos_avg_price !== 0)) {
//line pro avgp markers //line pro avgp markers
obj["time"] = timestamp; obj["time"] = timestamp;
obj["value"] = trade.pos_avg_price; obj["value"] = trade.pos_avg_price;
@ -87,12 +88,14 @@ function transform_data(data) {
a_markers["color"] = "#e8c76d" a_markers["color"] = "#e8c76d"
a_markers["shape"] = "arrowDown" a_markers["shape"] = "arrowDown"
//if (CHART_SHOW_TEXT) //if (CHART_SHOW_TEXT)
// a_markers["text"] = trade.position_qty + " " + parseFloat(trade.pos_avg_price).toFixed(3) //a_markers["text"] = trade.position_qty + " " + parseFloat(trade.pos_avg_price).toFixed(3)
a_markers["text"] = CHART_SHOW_TEXT ? trade.position_qty + "/" + parseFloat(trade.pos_avg_price).toFixed(3) :trade.position_qty //a_markers["text"] = CHART_SHOW_TEXT ? trade.position_qty + "/" + parseFloat(trade.pos_avg_price).toFixed(3) :trade.position_qty
avgp_markers.push(a_markers) avgp_markers.push(a_markers)
} }
} }
//buy sell markery //buy sell markery
marker = {} marker = {}
marker["time"] = timestamp; marker["time"] = timestamp;
@ -103,6 +106,7 @@ function transform_data(data) {
marker["shape"] = (trade.order.side == "buy") ? "circle" : "arrowDown" marker["shape"] = (trade.order.side == "buy") ? "circle" : "arrowDown"
//marker["text"] = trade.qty + "/" + trade.price //marker["text"] = trade.qty + "/" + trade.price
marker["text"] = CHART_SHOW_TEXT ? trade.qty + "/" + trade.price : trade.qty marker["text"] = CHART_SHOW_TEXT ? trade.qty + "/" + trade.price : trade.qty
marker["text"] = (trade.position_qty == 0) ? "c": marker["text"]
markers.push(marker) markers.push(marker)
//prevedeme iso data na timestampy //prevedeme iso data na timestampy

View File

@ -34,6 +34,7 @@ indConfig = [ {name: "ema", titlevisible: false, embed: true, display: true, pri
{name: "slopeS", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false}, {name: "slopeS", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
{name: "slopeLP", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false}, {name: "slopeLP", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
{name: "slopeMA", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false}, {name: "slopeMA", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
{name: "slopeLPMA", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
{name: "slow_slope", titlevisible: true, embed: true, display: false, priceScaleId: "left", lastValueVisible: false}, {name: "slow_slope", titlevisible: true, embed: true, display: false, priceScaleId: "left", lastValueVisible: false},
{name: "slow_slopeMA", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false}, {name: "slow_slopeMA", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
{name: "emaSlow", titlevisible: true, embed: true, display: true, priceScaleId: "right", lastValueVisible: false}, {name: "emaSlow", titlevisible: true, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},

View File

@ -0,0 +1,165 @@
from v2realbot.strategy.base import Strategy
from v2realbot.utils.utils import parse_alpaca_timestamp, ltp, AttributeDict,trunc,price2dec, zoneNY, print, json_serial, safe_get, get_tick
from v2realbot.utils.tlog import tlog, tlog_exception
from v2realbot.enums.enums import Mode, Order, Account, RecordType
from alpaca.trading.models import TradeUpdate
from alpaca.trading.enums import TradeEvent, OrderStatus
from v2realbot.indicators.indicators import ema
import json
#from rich import print
from random import randrange
from alpaca.common.exceptions import APIError
import copy
from threading import Event
from uuid import UUID
class StrategyClassicSL(Strategy):
"""
Base override file for Classic Stop-Loss startegy
"""
def __init__(self, name: str, symbol: str, next: callable, init: callable, account: Account, mode: Mode = Mode.PAPER, stratvars: AttributeDict = None, open_rush: int = 30, close_rush: int = 30, pe: Event = None, se: Event = None, runner_id: UUID = None, ilog_save: bool = False) -> None:
super().__init__(name, symbol, next, init, account, mode, stratvars, open_rush, close_rush, pe, se, runner_id, ilog_save)
#todo dodelat profit, podle toho jestli jde o short nebo buy
async def orderUpdateBuy(self, data: TradeUpdate):
o: Order = data.order
##nejak to vymyslet, aby se dal poslat cely Trade a serializoval se
self.state.ilog(e="Příchozí BUY notif", msg=o.status, trade=json.loads(json.dumps(data, default=json_serial)))
if o.status == OrderStatus.FILLED or o.status == OrderStatus.CANCELED:
#davame pryc pending
self.state.vars.pending = None
if data.event == TradeEvent.FILL or data.event == TradeEvent.PARTIAL_FILL:
#jde o uzavření short pozice - počítáme PROFIT
if self.state.positions < 0:
#PROFIT pocitame z TradeUpdate.price a TradeUpdate.qty - aktualne provedene mnozstvi a cena
#naklady vypocteme z prumerne ceny, kterou mame v pozicich
bought_amount = data.qty * data.price
#podle prumerne ceny, kolik stalo toto mnozstvi
avg_costs = float(self.state.avgp) * float(data.qty)
if avg_costs == 0:
self.state.ilog(e="ERR: Nemame naklady na PROFIT, AVGP je nula. Zaznamenano jako 0", msg="naklady=utrzena cena. TBD opravit.")
avg_costs = bought_amount
trade_profit = (avg_costs-bought_amount)
self.state.profit += trade_profit
self.state.ilog(e=f"BUY notif - SHORT PROFIT:{round(float(trade_profit),3)} celkem:{round(float(self.state.profit),3)}", msg=str(data.event), bought_amount=bought_amount, avg_costs=avg_costs, trade_qty=data.qty, trade_price=data.price, orderid=str(data.order.id))
else:
self.state.ilog(e="BUY: Jde o LONG nakuú nepocitame profit zatim")
#ic("vstupujeme do orderupdatebuy")
print(data)
#dostavame zde i celkové akutální množství - ukládáme
self.state.positions = data.position_qty
self.state.avgp, self.state.positions = self.state.interface.pos()
async def orderUpdateSell(self, data: TradeUpdate):
self.state.ilog(e="Příchozí SELL notif", msg=data.order.status, trade=json.loads(json.dumps(data, default=json_serial)))
#naklady vypocteme z prumerne ceny, kterou mame v pozicich
if data.event == TradeEvent.FILL or data.event == TradeEvent.PARTIAL_FILL:
if data.event == TradeEvent.FILL:
self.state.vars.pending = None
#jde o uzavření long pozice - počítáme PROFIT
if self.state.positions > 0:
#PROFIT pocitame z TradeUpdate.price a TradeUpdate.qty - aktualne provedene mnozstvi a cena
#naklady vypocteme z prumerne ceny, kterou mame v pozicich
sold_amount = data.qty * data.price
#podle prumerne ceny, kolik stalo toto mnozstvi
avg_costs = float(self.state.avgp) * float(data.qty)
if avg_costs == 0:
self.state.ilog(e="ERR: Nemame naklady na PROFIT, AVGP je nula. Zaznamenano jako 0", msg="naklady=utrzena cena. TBD opravit.")
avg_costs = sold_amount
trade_profit = (sold_amount - avg_costs)
self.state.profit += trade_profit
self.state.ilog(e=f"SELL notif - PROFIT:{round(float(trade_profit),3)} celkem:{round(float(self.state.profit),3)}", msg=str(data.event), sold_amount=sold_amount, avg_costs=avg_costs, trade_qty=data.qty, trade_price=data.price, orderid=str(data.order.id))
else:
self.state.ilog(e="SELL: Jde o SHORT nepocitame profit zatim")
#update pozic, v trade update je i pocet zbylych pozic
old_avgp = self.state.avgp
old_pos = self.state.positions
self.state.positions = int(data.position_qty)
if int(data.position_qty) == 0:
self.state.avgp = 0
self.state.ilog(e="SELL notifikace "+str(data.order.status), msg="update pozic", old_avgp=old_avgp, old_pos=old_pos, avgp=self.state.avgp, pos=self.state.positions, orderid=str(data.order.id))
#self.state.avgp, self.state.positions = self.interface.pos()
if data.event == TradeEvent.FILL or data.event == TradeEvent.CANCELED:
print("Příchozí SELL notifikace - complete FILL nebo CANCEL", data.event)
a,p = self.interface.pos()
#pri chybe api nechavame puvodni hodnoty
if a != -1:
self.state.avgp, self.state.positions = a,p
#ic(self.state.avgp, self.state.positions)
#this parent method is called by strategy just once before waiting for first data
def strat_init(self):
#ic("strat INI function")
#lets connect method overrides
self.state.buy = self.buy
self.state.sell = self.sell
#overidden methods
# pouziva se pri vstupu long nebo exitu short
# osetrit uzavreni s vice nez mam
def buy(self, size = None, repeat: bool = False):
print("overriden buy method")
if size is None:
sizer = self.state.vars.chunk
else:
sizer = size
#jde o uzavreni short pozice
if int(self.state.positions) < 0 and (int(self.state.positions) + sizer) > 0:
self.state.ilog(e="buy nelze nakoupit vic nez shortuji", positions=self.state.positions, size=size)
print("buy nelze nakoupit vic nez shortuji")
return -2
if int(self.state.positions) >= self.state.vars.maxpozic:
self.state.ilog(e="buy Maxim mnozstvi naplneno", positions=self.state.positions)
print("max mnostvi naplneno")
return 0
self.state.blockbuy = 1
self.state.vars.lastbuyindex = self.state.bars['index'][-1]
self.state.ilog(e="send MARKET buy to if", msg="S:"+str(size), ltp=self.state.interface.get_last_price(self.state.symbol))
return self.state.interface.buy(size=sizer)
#overidden methods
# pouziva se pri vstupu short nebo exitu long
def sell(self, size = None, repeat: bool = False):
print("overriden sell method")
if size is None:
size = abs(int(self.state.positions))
#jde o uzavreni long pozice
if int(self.state.positions) > 0 and (int(self.state.positions) - size) < 0:
self.state.ilog(e="nelze prodat vic nez longuji", positions=self.state.positions, size=size)
print("nelze prodat vic nez longuji")
return -2
#pokud shortuji a mam max pozic
if int(self.state.positions) < 0 and abs(int(self.state.positions)) >= self.state.vars.maxpozic:
self.state.ilog(e="short - Maxim mnozstvi naplneno", positions=self.state.positions, size=size)
print("max mnostvi naplneno")
return 0
#self.state.blocksell = 1
#self.state.vars.lastbuyindex = self.state.bars['index'][-1]
self.state.ilog(e="send MARKET SELL to if", msg="S:"+str(size), ltp=self.state.interface.get_last_price(self.state.symbol))
return self.state.interface.sell(size=size)
async def get_limitka_price(self):
def_profit = safe_get(self.state.vars, "def_profit")
if def_profit == None: def_profit = self.state.vars.profit
cena = float(self.state.avgp)
if await self.is_defensive_mode():
return price2dec(cena+get_tick(cena,float(def_profit)))
else:
return price2dec(cena+get_tick(cena,float(self.state.vars.profit)))

View File

@ -1,5 +1,5 @@
from v2realbot.strategy.base import Strategy from v2realbot.strategy.base import Strategy
from v2realbot.utils.utils import parse_alpaca_timestamp, ltp, AttributeDict,trunc,price2dec, zoneNY, print, json_serial, safe_get, get_tick from v2realbot.utils.utils import parse_alpaca_timestamp, ltp, AttributeDict,trunc,price2dec, zoneNY, json_serial, safe_get, get_tick,print
from v2realbot.utils.tlog import tlog, tlog_exception from v2realbot.utils.tlog import tlog, tlog_exception
from v2realbot.enums.enums import Mode, Order, Account, RecordType from v2realbot.enums.enums import Mode, Order, Account, RecordType
from alpaca.trading.models import TradeUpdate from alpaca.trading.models import TradeUpdate

View File

@ -2,7 +2,7 @@
Strategy base class Strategy base class
""" """
from datetime import datetime from datetime import datetime
from v2realbot.utils.utils import AttributeDict, zoneNY, is_open_rush, is_close_rush, json_serial, print, safe_get, Average from v2realbot.utils.utils import AttributeDict, zoneNY, is_open_rush, is_close_rush, json_serial, print
from v2realbot.utils.tlog import tlog from v2realbot.utils.tlog import tlog
from v2realbot.utils.ilog import insert_log, insert_log_multiple_queue from v2realbot.utils.ilog import insert_log, insert_log_multiple_queue
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Order, Account from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Order, Account

View File

@ -10,6 +10,7 @@ from v2realbot.enums.enums import RecordType, Mode, StartBarAlign
import pickle import pickle
import os import os
from v2realbot.common.model import StrategyInstance, Runner, RunArchive, RunArchiveDetail, Intervals from v2realbot.common.model import StrategyInstance, Runner, RunArchive, RunArchiveDetail, Intervals
from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus, TradeStoplossType
from typing import List from typing import List
import tomli import tomli
from v2realbot.config import DATA_DIR, QUIET_MODE,NORMALIZED_TICK_BASE_PRICE from v2realbot.config import DATA_DIR, QUIET_MODE,NORMALIZED_TICK_BASE_PRICE
@ -197,6 +198,8 @@ def json_serial(obj):
return obj.__dict__ return obj.__dict__
if type(obj) is RunArchive: if type(obj) is RunArchive:
return obj.__dict__ return obj.__dict__
if type(obj) is Trade:
return obj.__dict__
if type(obj) is RunArchiveDetail: if type(obj) is RunArchiveDetail:
return obj.__dict__ return obj.__dict__
if type(obj) is Intervals: if type(obj) is Intervals: