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 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

View File

@ -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'))

View File

@ -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)

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.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]

View File

@ -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]
#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,29 +488,51 @@ 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)
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 - 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)))
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())

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:
# 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

View File

@ -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

View File

@ -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)

View File

@ -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*"*")

View File

@ -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;
@ -88,11 +89,13 @@ function transform_data(data) {
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"] = 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

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: "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},

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.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

View File

@ -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

View File

@ -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: