draft nove classis strategie
This commit is contained in:
14
alpacawebsokcet.py
Normal file
14
alpacawebsokcet.py
Normal 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()
|
||||
@ -4,7 +4,7 @@ from alpaca.trading.stream import TradingStream
|
||||
from alpaca.data.enums import DataFeed
|
||||
from config import API_KEY, SECRET_KEY, MAX_BATCH_SIZE
|
||||
from datetime import datetime
|
||||
import mplfinance as mpf
|
||||
#import mplfinance as mpf
|
||||
import matplotlib.pyplot as plt
|
||||
import threading
|
||||
# pripadne parametry pro request
|
||||
|
||||
@ -1039,6 +1039,9 @@ res = dict(zip(max_positions['qty'], max_positions['count']))
|
||||
|
||||
ouput_dict=dict(maxpos=str(res))
|
||||
|
||||
all_summary = trade_df.describe(include='all')
|
||||
print(all_summary)
|
||||
|
||||
print(ouput_dict)
|
||||
#a = trade_df.value_counts(subset=['position_qty'])
|
||||
#print(max_positions.to_dict('records'))
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
from threading import Thread, current_thread
|
||||
import threading
|
||||
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
|
||||
from alpaca.data.enums import DataFeed
|
||||
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)
|
||||
"""""
|
||||
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 = []
|
||||
lock = threading.Lock()
|
||||
|
||||
@ -124,12 +124,12 @@ class WS_Stream(Thread):
|
||||
# novy ws stream - vždy jednom vláknu
|
||||
obj= WS_Stream(name="jednicka")
|
||||
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)
|
||||
print("1", WS_Stream._streams)
|
||||
# novy ws stream - vždy jednom vláknu
|
||||
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)
|
||||
print("2", WS_Stream._streams)
|
||||
obj.start()
|
||||
@ -141,7 +141,7 @@ print("po startu druheho")
|
||||
time.sleep(2)
|
||||
print("pridavame treti")
|
||||
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.start()
|
||||
print(WS_Stream._streams)
|
||||
|
||||
1065
v2realbot/ENTRY_ClassicSL_v01.py
Normal file
1065
v2realbot/ENTRY_ClassicSL_v01.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@ from v2realbot.strategy.StrategyOrderLimitVykladaciNormalizedMYSELL import Strat
|
||||
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide, OrderType
|
||||
from v2realbot.indicators.indicators import ema
|
||||
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 icecream import install, ic
|
||||
#from rich import print
|
||||
@ -536,6 +536,7 @@ def next(data, state: StrategyState):
|
||||
#u indikatoru muzoun byt tyto directivy pro generovani buysignalu
|
||||
# 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 - kdyz krosne obema smery, VALUE: hodnota nebo nazev indikatoru
|
||||
# buy_if_falling - kdyz je klesajici 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
|
||||
@ -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))
|
||||
elif directive.endswith("crossed_up"):
|
||||
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"):
|
||||
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"):
|
||||
@ -618,7 +622,6 @@ def next(data, state: StrategyState):
|
||||
|
||||
return cond
|
||||
|
||||
|
||||
#tato funkce vytvori dictionary typu podminek (OR/AND)
|
||||
# z indikatoru, ktere obsahuji direktivami daneho typu(buy_if, dont_buy_when)
|
||||
# v tuplu (nazevind,direktiva,hodnota)
|
||||
@ -650,6 +653,12 @@ def next(data, state: StrategyState):
|
||||
except KeyError:
|
||||
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
|
||||
def buy_if_crossed_down(indicator, value):
|
||||
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)
|
||||
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
|
||||
#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)
|
||||
@ -862,10 +875,11 @@ def next(data, state: StrategyState):
|
||||
lookbacktime = state.bars.time[-slope_lookback]
|
||||
|
||||
#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))
|
||||
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:
|
||||
#dame na porovnani jen prumer
|
||||
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)
|
||||
|
||||
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:
|
||||
#kdyz neni dostatek hodnot, pouzivame jako levy bod open hodnotu close[0]
|
||||
lookbackprice = state.bars.close[0]
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -87,6 +87,7 @@ class Backtester:
|
||||
self.bp_from = bp_from
|
||||
self.bp_to = bp_to
|
||||
self.cash = cash
|
||||
self.cash_reserved_for_shorting = 0
|
||||
self.trades = []
|
||||
self.account = { "BAC": [0, 0] }
|
||||
# { "BAC": [avgp, size] }
|
||||
@ -372,23 +373,43 @@ class Backtester:
|
||||
|
||||
if o.side == OrderSide.BUY:
|
||||
#[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:
|
||||
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)
|
||||
return 1
|
||||
#sell
|
||||
elif o.side == OrderSide.SELL:
|
||||
newsize = self.account[o.symbol][0]-o.qty
|
||||
#UPLNE UZAVRENI LONGU (avgp 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:
|
||||
#pokud je predchozi 0 - tzn. jde o prvni short
|
||||
if self.account[o.symbol][1] == 0:
|
||||
newavgp = o.filled_avg_price
|
||||
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.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
|
||||
else:
|
||||
print("neznaama side", o.side)
|
||||
@ -467,31 +488,53 @@ class Backtester:
|
||||
#check for available quantity
|
||||
if side == OrderSide.SELL:
|
||||
reserved = 0
|
||||
reserved_price = 0
|
||||
#with lock:
|
||||
for o in self.open_orders:
|
||||
if o.side == OrderSide.SELL and o.symbol == symbol and o.canceled_at is None:
|
||||
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:
|
||||
print("not enough shares having",self.account[symbol][0],"reserved",reserved,"available",int(self.account[symbol][0]) - reserved,"selling",size)
|
||||
actual_minus_reserved = int(self.account[symbol][0]) - reserved
|
||||
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
|
||||
|
||||
#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
|
||||
if side == OrderSide.BUY:
|
||||
reserved = 0
|
||||
reserved_qty = 0
|
||||
reserved_price = 0
|
||||
#with lock:
|
||||
for o in self.open_orders:
|
||||
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)
|
||||
reserved += o.qty * cena
|
||||
print("blokovano v open orders: ", reserved)
|
||||
reserved_price += o.qty * cena
|
||||
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)
|
||||
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)))
|
||||
actual_plus_reserved_qty = int(self.account[symbol][0]) + reserved_qty
|
||||
|
||||
#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
|
||||
|
||||
#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())
|
||||
order = Order(id=id,
|
||||
submitted_at = datetime.fromtimestamp(float(time)),
|
||||
|
||||
27
v2realbot/common/PrescribedTradeModel.py
Normal file
27
v2realbot/common/PrescribedTradeModel.py
Normal 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
|
||||
|
||||
Binary file not shown.
@ -18,13 +18,12 @@ from alpaca.data.enums import Exchange
|
||||
# if user_update.first_name is not None:
|
||||
# user.first_name = user_update.first_name
|
||||
# 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:
|
||||
# user.roles = user_update.roles
|
||||
# return user.id
|
||||
# raise HTTPException(status_code=404, detail=f"Could not find user with id: {id}")
|
||||
|
||||
|
||||
class Intervals(BaseModel):
|
||||
start: str
|
||||
end: str
|
||||
|
||||
@ -92,8 +92,8 @@ ACCOUNT1_LIVE_PAPER = False
|
||||
ACCOUNT1_LIVE_FEED = DataFeed.SIP
|
||||
|
||||
#SECONDARY PAPER
|
||||
ACCOUNT2_PAPER_API_KEY = 'PKQEAAJTVC72SZO3CT3R'
|
||||
ACCOUNT2_PAPER_SECRET_KEY = 'mqdftzGJlJdvUjdsuQynAURCHRwAI0a8nhJy8nyz'
|
||||
ACCOUNT2_PAPER_API_KEY = 'PK0OQHZG03PUZ1SC560V'
|
||||
ACCOUNT2_PAPER_SECRET_KEY = 'cTglhm7kwRcZfFT27fQWz31sXaxadzQApFDW6Lat'
|
||||
ACCOUNT2_PAPER_MAX_BATCH_SIZE = 1
|
||||
ACCOUNT2_PAPER_PAPER = True
|
||||
ACCOUNT2_PAPER_FEED = DataFeed.IEX
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -11,7 +11,7 @@ import threading
|
||||
from copy import deepcopy
|
||||
from msgpack import unpackb
|
||||
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:
|
||||
def __init__(self,
|
||||
@ -383,7 +383,7 @@ class TradeAggregator2Queue(TradeAggregator):
|
||||
copy = obj
|
||||
|
||||
##populate secondary resolution if required
|
||||
|
||||
#print("inserted to queue")
|
||||
self.queue.put(copy)
|
||||
res = []
|
||||
#print("po insertu",res)
|
||||
|
||||
@ -42,17 +42,19 @@ class Trade_Offline_Streamer(Thread):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
#create new asyncio loop in the thread
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
loop.create_task(self.main())
|
||||
loop.run_forever()
|
||||
self.main()
|
||||
# #create new asyncio loop in the thread
|
||||
# loop = asyncio.new_event_loop()
|
||||
# asyncio.set_event_loop(loop)
|
||||
# loop.create_task(self.main())
|
||||
# loop.run_forever()
|
||||
|
||||
def stop(self):
|
||||
pass
|
||||
|
||||
# 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*"*")
|
||||
|
||||
if not self.streams:
|
||||
@ -194,16 +196,24 @@ class Trade_Offline_Streamer(Thread):
|
||||
for s in self.to_run[symbol]:
|
||||
#print("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
|
||||
#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)
|
||||
#po loadovani vsech dnu
|
||||
print("naloadovane vse posilame last")
|
||||
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")
|
||||
loop.stop()
|
||||
#loop.stop()
|
||||
print(10*"*","Trade OFFLINE streamer STOPPED", current_thread().name,10*"*")
|
||||
|
||||
|
||||
|
||||
@ -72,10 +72,11 @@ function transform_data(data) {
|
||||
last_timestamp = timestamp
|
||||
iterator = 0.002
|
||||
}
|
||||
|
||||
if (trade.order.side == "buy") {
|
||||
//puvodne bylo pro 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
|
||||
if (trade.pos_avg_price !== null) {
|
||||
if ((trade.pos_avg_price !== null) && (trade.pos_avg_price !== 0)) {
|
||||
//line pro avgp markers
|
||||
obj["time"] = timestamp;
|
||||
obj["value"] = trade.pos_avg_price;
|
||||
@ -87,12 +88,14 @@ function transform_data(data) {
|
||||
a_markers["color"] = "#e8c76d"
|
||||
a_markers["shape"] = "arrowDown"
|
||||
//if (CHART_SHOW_TEXT)
|
||||
// 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"] = 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
|
||||
avgp_markers.push(a_markers)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//buy sell markery
|
||||
marker = {}
|
||||
marker["time"] = timestamp;
|
||||
@ -103,6 +106,7 @@ function transform_data(data) {
|
||||
marker["shape"] = (trade.order.side == "buy") ? "circle" : "arrowDown"
|
||||
//marker["text"] = trade.qty + "/" + trade.price
|
||||
marker["text"] = CHART_SHOW_TEXT ? trade.qty + "/" + trade.price : trade.qty
|
||||
marker["text"] = (trade.position_qty == 0) ? "c": marker["text"]
|
||||
markers.push(marker)
|
||||
|
||||
//prevedeme iso data na timestampy
|
||||
|
||||
@ -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: "slopeLP", 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_slopeMA", titlevisible: true, embed: true, display: true, priceScaleId: "left", lastValueVisible: false},
|
||||
{name: "emaSlow", titlevisible: true, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},
|
||||
|
||||
165
v2realbot/strategy/StrategyClassicSL.py
Normal file
165
v2realbot/strategy/StrategyClassicSL.py
Normal 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)))
|
||||
@ -1,5 +1,5 @@
|
||||
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.enums.enums import Mode, Order, Account, RecordType
|
||||
from alpaca.trading.models import TradeUpdate
|
||||
|
||||
Binary file not shown.
@ -2,7 +2,7 @@
|
||||
Strategy base class
|
||||
"""
|
||||
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.ilog import insert_log, insert_log_multiple_queue
|
||||
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Order, Account
|
||||
|
||||
Binary file not shown.
@ -10,6 +10,7 @@ from v2realbot.enums.enums import RecordType, Mode, StartBarAlign
|
||||
import pickle
|
||||
import os
|
||||
from v2realbot.common.model import StrategyInstance, Runner, RunArchive, RunArchiveDetail, Intervals
|
||||
from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus, TradeStoplossType
|
||||
from typing import List
|
||||
import tomli
|
||||
from v2realbot.config import DATA_DIR, QUIET_MODE,NORMALIZED_TICK_BASE_PRICE
|
||||
@ -197,6 +198,8 @@ def json_serial(obj):
|
||||
return obj.__dict__
|
||||
if type(obj) is RunArchive:
|
||||
return obj.__dict__
|
||||
if type(obj) is Trade:
|
||||
return obj.__dict__
|
||||
if type(obj) is RunArchiveDetail:
|
||||
return obj.__dict__
|
||||
if type(obj) is Intervals:
|
||||
|
||||
Reference in New Issue
Block a user