first commit

This commit is contained in:
David Brazda
2023-04-12 21:00:03 +02:00
commit af9e944928
158 changed files with 19422 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/.DS_Store
/v2realbot.egg-info

34
.gtignore Normal file
View File

@ -0,0 +1,34 @@
/__pycache__/
/backtestresults/
/cache/
/v2realbot/backtestresults/
/v2realbot/cache/
/v2realbot/__pycache__/
/.vscode/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

18
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,18 @@
{
// Pro informace o možných atributech použijte technologii IntelliSense.
// Umístěním ukazatele myši zobrazíte popisy existujících atributů.
// Další informace najdete tady: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: Aktuální soubor",
"type": "python",
"request": "launch",
"program": "${file}",
"cwd": "${workspaceFolder}",
"env": {"PYTHONPATH": "${workspaceFolder}:${workspaceFolder}/bld"},
"console": "integratedTerminal",
"justMyCode": true
}
]
}

6
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,6 @@
{
"python.analysis.logLevel": "Trace",
"terminal.integrated.env.osx": {
"PYTHONPATH": "${workspaceFolder}/"
}
}

96
requirements.txt Normal file
View File

@ -0,0 +1,96 @@
alpaca==1.0.0
alpaca-py==0.7.1
altair==4.2.2
anyio==3.6.2
appdirs==1.4.4
asttokens==2.2.1
attrs==22.2.0
better-exceptions==0.3.3
bleach==6.0.0
blinker==1.5
cachetools==5.3.0
certifi==2022.12.7
chardet==5.1.0
charset-normalizer==3.0.1
click==8.1.3
contourpy==1.0.7
cycler==0.11.0
dash==2.9.1
dash-bootstrap-components==1.4.1
dash-core-components==2.0.0
dash-html-components==2.0.0
dash-table==5.0.0
decorator==5.1.1
entrypoints==0.4
executing==1.2.0
fastapi==0.95.0
Flask==2.2.3
fonttools==4.39.0
gitdb==4.0.10
GitPython==3.1.31
h11==0.14.0
icecream==2.1.3
idna==3.4
importlib-metadata==6.1.0
itsdangerous==2.1.2
jsonschema==4.17.3
kiwisolver==1.4.4
Markdown==3.4.3
markdown-it-py==2.2.0
MarkupSafe==2.1.2
mdurl==0.1.2
msgpack==1.0.4
newtulipy==0.4.6
numpy==1.24.2
packaging==23.0
pandas==1.5.3
param==1.13.0
Pillow==9.4.0
plotly==5.13.1
proto-plus==1.22.2
protobuf==3.20.3
pyarrow==11.0.0
pyasn1==0.4.8
pyasn1-modules==0.2.8
pyct==0.5.0
pydantic==1.10.5
pydeck==0.8.0
Pygments==2.14.0
Pympler==1.0.1
pyparsing==3.0.9
pyrsistent==0.19.3
pysos==1.3.0
python-dateutil==2.8.2
python-dotenv==1.0.0
pytz==2022.7.1
pytz-deprecation-shim==0.1.0.post0
pyviz-comms==2.2.1
PyYAML==6.0
requests==2.28.2
rich==13.3.1
rsa==4.9
seaborn==0.12.2
semver==2.13.0
six==1.16.0
smmap==5.0.0
sniffio==1.3.0
sseclient-py==1.7.2
starlette==0.26.1
streamlit==1.20.0
structlog==23.1.0
tenacity==8.2.2
toml==0.10.2
tomli==2.0.1
toolz==0.12.0
tornado==6.2
tqdm==4.65.0
typing_extensions==4.5.0
tzdata==2023.2
tzlocal==4.3
urllib3==1.26.14
uvicorn==0.21.1
validators==0.20.0
webencodings==0.5.1
websockets==10.4
Werkzeug==2.2.3
zipp==3.15.0

9
setup.py Normal file
View File

@ -0,0 +1,9 @@
from setuptools import find_packages, setup
setup(name='v2realbot',
version='0.9',
description='Realbot trader',
author='David Brazda',
author_email='davidbrazda61@gmail.com',
packages=find_packages()
)

27
testy/archive/.gtignore Normal file
View File

@ -0,0 +1,27 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
cache/

Binary file not shown.

View File

@ -0,0 +1,52 @@
from alpaca.data.historical import CryptoHistoricalDataClient, StockHistoricalDataClient
from alpaca.data.requests import CryptoLatestTradeRequest, StockLatestTradeRequest, StockLatestBarRequest, StockTradesRequest, StockBarsRequest
from alpaca.data.enums import DataFeed
from config import API_KEY, SECRET_KEY, MAX_BATCH_SIZE
import datetime
import time
from alpaca.data import Quote, Trade, Snapshot, Bar
from alpaca.data.models import BarSet, QuoteSet, TradeSet
from alpaca.data.timeframe import TimeFrame
import mplfinance as mpf
import pandas as pd
parametry = {}
# no keys required
#client = CryptoHistoricalDataClient()
client = StockHistoricalDataClient(API_KEY, SECRET_KEY, raw_data=False)
datetime_object_from = datetime.datetime(2023, 2, 27, 18, 51, 38, tzinfo=datetime.timezone.utc)
datetime_object_to = datetime.datetime(2023, 2, 27, 21, 51, 39, tzinfo=datetime.timezone.utc)
bar_request = StockBarsRequest(symbol_or_symbols="BAC",timeframe=TimeFrame.Hour, start=datetime_object_from, end=datetime_object_to, feed=DataFeed.SIP)
bars = client.get_stock_bars(bar_request).df
#bars = bars.drop(['symbol'])
#print(bars.df.close)
bars = bars.tz_convert('America/New_York')
print(bars)
print(bars.df.columns)
#Index(['open', 'high', 'low', 'close', 'volume', 'trade_count', 'vwap'], dtype='object')
bars.df.set_index('timestamp', inplace=True)
mpf.plot(bars.df, # the dataframe containing the OHLC (Open, High, Low and Close) data
type='candle', # use candlesticks
volume=True, # also show the volume
mav=(3,6,9), # use three different moving averages
figratio=(3,1), # set the ratio of the figure
style='yahoo', # choose the yahoo style
title='Prvni chart');
# #vrací se list od dict
# print(bars["BAC"])
# # k nemu muzeme pristupovat s
# dict = bars["BAC"]
# print(type(dict))
# print(dict[2].timestamp)
# print(dict[2].close)
# print(dict[].close)

View File

@ -0,0 +1,51 @@
#udajne working example for using a minute
# timeframe in backtrader with alpaca api
import alpaca_backtrader_api
import backtrader as bt
import pandas as pd
from datetime import datetime
from strategies.tos_strategy import TOS
from dotenv import load_dotenv
import os
load_dotenv()
api_key = os.getenv('API_KEY_ID')
api_secret = os.getenv('API_SECRET')
alpaca_paper = os.getenv('ALPACA_PAPER')
cerebro = bt.Cerebro()
cerebro.addstrategy(TOS)
cerebro.broker.setcash(100000)
cerebro.broker.setcommission(commission=0.0)
cerebro.addsizer(bt.sizers.PercentSizer, percents=20)
store = alpaca_backtrader_api.AlpacaStore(
key_id=api_key,
secret_key=api_secret,
paper=alpaca_paper
)
if not alpaca_paper:
broker = store.getbroker() # or just alpaca_backtrader_api.AlpacaBroker()
cerebro.setbroker(broker)
DataFactory = store.getdata # or use alpaca_backtrader_api.AlpacaData
data0 = DataFactory(
dataname='AAPL',
timeframe=bt.TimeFrame.TFrame("Minutes"),
fromdate=pd.Timestamp('2018-11-15'),
todate=pd.Timestamp('2018-11-17'),
historical=True)
cerebro.adddata(data0)
#Resampler for 15 minutes
cerebro.resampledata(data0,timeframe=bt.TimeFrame.Minutes,compression=15)
print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
cerebro.run()
print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
cerebro.plot()

View File

@ -0,0 +1,172 @@
# použití websocket loaderu v samostatném threadu
# v dalsim threadu pak input a cteni globalniho dataframu
# a stopnutí websocket loopu
#import clients
from alpaca.data.live import StockDataStream, CryptoDataStream
from alpaca.data.enums import DataFeed
from config import API_KEY, SECRET_KEY, MAX_BATCH_SIZE
from datetime import datetime
import pandas as pd
import threading
# pripadne parametry pro request
# parametry = {
# "brand": "Ford",
# "model": "Mustang",
# "year": 1964
# }
sloupce=["timestamp","price","size","condition"]
sloupce_q=["timestamp","ask_size","ask_price","bid_price","bid_ask"]
# deklarace globalniho df s timeindexem
gdf = pd.DataFrame(columns=sloupce, index=pd.to_datetime([]))
gdf_q = pd.DataFrame(columns=sloupce_q, index=pd.to_datetime([]))
# # pro komunikaci mezi thready budeme pouzivat globalni variable
# # pro zamezeni race condition pouzijeme mutual lock (mutex)
# create a lock
# lock = threading.Lock()
# with lock:
# # add to the variable
# variable = variable + 10
# # release the lock automatically
prev_timestamp = "new"
batch = []
batch_q = []
seconds_list = []
parametry = {}
now = datetime.now() # current date and time aware of timezones
now = now.astimezone()
# client musi byt globalni, aby ho druhy thread dokazal stopnout
#client = StockDataStream(API_KEY, SECRET_KEY, raw_data=False, websocket_params=parametry, feed=DataFeed.SIP)
client = StockDataStream(API_KEY, SECRET_KEY, raw_data=True, websocket_params=parametry, feed=DataFeed.SIP)
## thread pro cteni websocketu a plneni glob.dataframu
# pozdeji prepsat do samostatne Class WSReader
def ws_reader():
print("vstup do threadu ws reader")
#handler pro ws trader data
async def data_handler(data):
global gdf
global batch
#record_list = (data.timestamp, data.open,data.high,data.low,data.close)
#batch.append(record_list)
print(data)
# kazdou davku pak zapiseme do datasetu
if len(batch) == MAX_BATCH_SIZE:
## z aktualniho listu batch udelame DataFrame
new_df = pd.DataFrame.from_records(data=batch, columns = sloupce)
## tento dataframe pridame ke globalnimu
gdf = pd.concat([gdf,new_df], axis=0, ignore_index=True)
batch = []
#print(gdf)
#handler pro ws quote data
async def data_handler_q(data):
global gdf_q
global batch_q
global prev_timestamp
global seconds_list
record_list = (data.timestamp, data.ask_size,data.ask_price,data.bid_price,data.bid_size)
batch_q.append(record_list)
#print(data.ask_size,data.ask_price,data.bid_price,data.bid_size)
#print("sestaveni je",sestaveni, "\\n batch ma ", len(batch), "clenu")
print(batch_q)
##max a min hodnota z druhych hodnot listu
def max_value(inputlist):
return max([sublist[1] for sublist in inputlist])
def min_value(inputlist):
return min([sublist[1] for sublist in inputlist])
def sum_value(inputlist):
for sublist in inputlist: print(sublist[-1])
return sum([sublist[-1] for sublist in inputlist])
#pokud jde o stejnou vterinu nebo o prvni zaznam, pridame do pole
if (prev_timestamp=="new") or (data.timestamp.second==prev_timestamp.second):
print("stejna vterina")
seconds_list.append([data.timestamp, data.ask_price, data.ask_size])
#print("po appendu",seconds_list)
else:
print("nova vterina")
# dopocitame ohlc
print("max", max_value(seconds_list), "min ", min_value(seconds_list), "sum", sum_value(seconds_list), "open", seconds_list[0][1], "close", seconds_list[-1][1])
print("-"*40)
seconds_list = []
seconds_list.append([data.timestamp, data.ask_price, data.ask_size])
print(seconds_list)
#vypisu z listu
print("akt.cas",data.timestamp,"minuly cas", prev_timestamp)
prev_timestamp = data.timestamp
# kazdou davku pak zapiseme do datasetu
if len(batch_q) == MAX_BATCH_SIZE:
## z aktualniho listu batch udelame DataFrame
new_df = pd.DataFrame.from_records(data=batch_q, columns = sloupce_q)
## tento dataframe pridame ke globalnimu
gdf_q = pd.concat([gdf_q,new_df], axis=0, ignore_index=True)
batch_q = []
#print(gdf)t
#client.subscribe_quotes(data_handler, "BAC")
#client.subscribe_trades(data_handler, "BAC")
#client.subscribe_updated_bars(data_handler, "BAC")
## taddy to ceka a bezi
print("spoustim run")
client.run()
print("run skoncil")
def user_prompt():
print("Tady je druhy thread, kde muzu delat co chci, pripadne ovladat ws loader")
while True:
delej = input("Vypsat dataframe: [t-trades;q-quotes;e-exit]")
if delej == "t": print(gdf)
elif delej =="q": print(gdf_q.tail(20))
elif delej =="e": break
print("bye")
client.stop()
def main():
# definujeme thready
t1 = threading.Thread(target=ws_reader)
#t2 = threading.Thread(target=user_prompt)
#spustime thready
t1.start()#, t2.start()
# Wait threads to complete
t1.join()#, t2.join()
if __name__ == "__main__":
main()
# tbd jeste si vyzkouset, zda to bez threadu nepujde takto s asynciem
# if __name__ == '__main__':
# logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
# level=logging.INFO)
# logging.log(logging.INFO, 'Starting up...')
# try:
# loop = asyncio.get_event_loop()
# loop.run_until_complete(main())
# loop.close()
# except KeyboardInterrupt:
# pass

View File

@ -0,0 +1,39 @@
from alpaca.data.historical import CryptoHistoricalDataClient, StockHistoricalDataClient
from alpaca.data.requests import CryptoLatestTradeRequest, StockLatestTradeRequest, StockLatestBarRequest, StockTradesRequest
from alpaca.data.enums import DataFeed
from config import API_KEY, SECRET_KEY, MAX_BATCH_SIZE
import datetime
import time
parametry = {}
# no keys required
#client = CryptoHistoricalDataClient()
client = StockHistoricalDataClient(API_KEY, SECRET_KEY, raw_data=True)
# single symbol request
#request_trade_params = StockTradesRequest(symbol_or_symbols="BAC", feed = DataFeed.SIP)
#request_last_bar_params = StockLatestBarRequest(symbol_or_symbols="BAC", feed=DataFeed.SIP)
#2023, 2, 27, 18, 51, 38
datetime_object_from = datetime.datetime(2023, 2, 26, 17, 51, 38, tzinfo=datetime.timezone.utc)
datetime_object_to = datetime.datetime(2023, 2, 28, 17, 51, 39, tzinfo=datetime.timezone.utc)
trades_request = StockTradesRequest(symbol_or_symbols="C", feed = DataFeed.SIP, start=datetime_object_from, end=datetime_object_to)
#latest_trade = client.get_stock_latest_trade(request_trade_params)
#latest_bar = client.get_stock_latest_bar(request_last_bar_params)
# for i in range(1,1000):
# latest_bar = client.get_stock_latest_bar(request_last_bar_params)
# data = latest_bar['BAC']
# print(data.timestamp,data.trade_count, data.trade_count, data.high, data.low, data.close, data.volume, data.vwap)
# time.sleep(1)
all_trades = client.get_stock_trades(trades_request)
# must use symbol to access even though it is single symbol
# print("last trade",latest_trade)
# print("latest bar",latest_bar)
# print("Trades Today", all_trades)
print(len(all_trades["C"]))

View File

@ -0,0 +1,66 @@
# 2 clients for historical data StockHistoricalDataClient (needs keys), CryptoHistoricalDataClient
# 2 clients for real time data CryptoDataStream, StockDataStream
# naimportuju si daneho clienta
from alpaca.data.historical import StockHistoricalDataClient, CryptoHistoricalDataClient
#pokdu pouzivam historicke data(tzn. REST) tak si naimportuju dany request object
from alpaca.data.requests import StockLatestQuoteRequest, StockBarsRequest, StockTradesRequest
#objekty se kterymi pak pracuju (jsou soucasi package výše, tady jen informačně)
from alpaca.data import Quote, Trade, Snapshot, Bar
from alpaca.data.models import BarSet, QuoteSet, TradeSet
from config import API_KEY, SECRET_KEY
from datetime import datetime, timedelta
import pandas as pd
import rich
# vytvorim si clienta
stock_client = StockHistoricalDataClient(API_KEY, SECRET_KEY, raw_data=True)
crypto_client = CryptoHistoricalDataClient()
time_from = datetime(2023, 2, 17, 14, 30, 0, 0)
time_to = datetime(2023, 2, 17, 14, 30, 1, 0)
#print(time_from)
# vytvorim request objekt
#latestQuoteRequest = StockLatestQuoteRequest(symbol_or_symbols=["SPY", "GLD", "TLT"])
stockTradeRequest = StockTradesRequest(symbol_or_symbols=["BAC","C","MSFT"], start=time_from,end=time_to)
#zavolam na clientovi metodu s request objektem, vrací se mi Dict[str, Quote] - obj.Quote pro kazdy symbol
#latestQuoteObject = stock_client.get_stock_latest_quote(latestQuoteRequest)
tradesResponse = stock_client.get_stock_trades(stockTradeRequest)
print(tradesResponse)
for i in tradesResponse['BAC']:
print(i)
# vrací m to tradeset dict = Trades identifikovane symbolem
#for
#access as a list
#print(tradesResponse["BAC"])
# The scope of these changes made to
# pandas settings are local to with statement.
# with pd.option_context('display.max_rows', None,
# 'display.max_columns', None,
# 'display.precision', 3,
# ):
# #convert to dataframe
# print(tradesResponse.df)
# this is the Quote object for
#bacquote=latestQuoteObject["SPY"]
# print(bacquote)
#vrati se mi objekt typu LatestQuote
# print(type(latestQuoteObject))
# print(latestQuoteObject)
#gld_latest_ask_price = latestQuoteObject["GLD"].ask_price
#print(gld_latest_ask_price, latestQuoteObject["GLD"].timestamp)

View File

@ -0,0 +1,74 @@
from alpaca.data.live import StockDataStream, CryptoDataStream
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 matplotlib.pyplot as plt
import threading
# pripadne parametry pro request
# parametry = {
# "brand": "Ford",
# "model": "Mustang",
# "year": 1964
# }
parametry = {}
i = 0
u = 0
async def data_handler1(data):
print("HANDLER1")
global i
i += 1
print(data)
async def data_handler2(data):
print("HANDLER2")
global u
u += 1
print(data)
async def data_handler3(data):
print("HANDLER3")
global u
u += 1
print(data)
# plt.ion()
# def animate(ival):
# # PREPARE DATAFRAME WITH OHLC AND "BUYS" AND "SELLS" HERE
# apds = [mpf.make_addplot(buys, color='tab:green', ax=ax_buys),
# mpf.make_addplot(sells, color='tab:red', ax=ax_sells)]
# for ax in axes:
# ax.clear()
# mpf.plot(df_ohlc, type='candle', addplot=apds, ax=ax_main)
# print('a')
#client = CryptoDataStream(API_KEY, SECRET_KEY, raw_data=True, websocket_params=parametry)
client1 = TradingStream(API_KEY, SECRET_KEY, paper=True)
client1.subscribe_trade_updates(data_handler1)
t1 = threading.Thread(target=client1.run)
t1.start()
print("started1")
client2 = TradingStream(API_KEY, SECRET_KEY, paper=True)
client2.subscribe_trade_updates(data_handler2)
t2 = threading.Thread(target=client2.run)
t2.start()
client3 = TradingStream(API_KEY, SECRET_KEY, paper=True)
client3.subscribe_trade_updates(data_handler3)
t3 = threading.Thread(target=client3.run)
t3.start()
print("started2")
print(threading.enumerate())
t2.join()
t1.join()
t3.join()
# client.subscribe_trades(data_handler, "BTC/USD")
# #client.subscribe_quotes(data_handler_ETH, "ETH/USD")
# print("pred spustenim runu")
# client.run()
# print("po spusteni runu - muzu neco delat?")

47
testy/archive/async.py Normal file
View File

@ -0,0 +1,47 @@
#Asyncio - umoznuje a řídí konkurentni kod (v ramci jednoho vlakna, vice vlaken nebo i procesu - skrz concurrent.futures)
# async si pri definici oznacim funkci, kterou chci asynchronne volat a ve které muze byt dalsi asynchronni volani(await)
# await - označuje mi, že na volanou funkci čekám - pokud je pouzito v tasku pak task vraci pokračování zpět o level výše
# create task(asynchr.funkce) - vtakto zavolám paralelni funkci bez cekani a blok pokracuje dal
# asyncio.wait - ceka na tas
# Here is a list of what you need in order to make your program async:
# Add async keyword in front of your function declarations to make them awaitable.
# Add await keyword when you call your async functions (without it they wont run).
# Create tasks from the async functions you wish to start asynchronously. Also wait for their finish.
# Call asyncio.run to start the asynchronous section of your program. Only one per thread.
# time.sleep(5) - blokuje, await asyncio.sleep(5) - neblokuje kod(asynchroni task)
import asyncio
#tbd pridat logger
async def makej(pracant, cekani):
print("pracant ",pracant, "zacal", "bude cekat",cekani,"sekubd")
await asyncio.sleep(cekani)
print("pracant ",pracant,"docekal",cekani,"sekund")
async def main():
print("vstup do funkce main")
#vytvoreni asynchronnich tasků
task1 = asyncio.create_task(makej(1,5))
task2 = asyncio.create_task(makej(2,3))
task3 = asyncio.create_task(makej(3,1))
print("tasky jedou - ted jsme v kodu za jejich spustenim - ale pred await.wait")
#budeme cekat na dokonceni tasků
await asyncio.wait([task1,task2,task3])
print("dočekáno na vysledek po volani await.wait")
print("a ted volani funkce standardním synchro způsobem, kdy cekame na vysledek ")
#volani funkce standardním synchro způsobem, kdy cekame na vysledek
await makej(1,1)
await makej(2,1)
# hlavni volani - run by mela byt jedna pro jedno vlakno
#asyncio.run(main())
#feature to convert async to sync
#asyncio.get_event_loop().run_until_complete() --nebo je tu tento decorator https://github.com/miyakogi/syncer
newfeature = asyncio.run(makej(1,1))

View File

@ -0,0 +1,57 @@
# to test change iterable (adding items) while iterating
class Notif:
def __init__(self,time):
self.time = time
open_orders = []
for i in range(1,10):
open_orders.append(Notif(i))
print("cele pole objektu",open_orders)
# Here, 'reversed' returns a lazy iterator, so it's performant! reversed(l):
#musi fungovat removing stare a pridavani novych
#this list contains all not processed notification, that we try to process during this iteration
#if time is not right we leave the message for next iter
#if time is right we process the message (- note it can trigger additional open_orders, that are added to queue)
def process_message(notif: Notif):
global open_orders
if notif.time % 2 == 0 and notif.time < 300:
open_orders.append(Notif(notif.time+50))
todel = []
for i in open_orders:
print("*******start iterace polozky", i.time)
process_message(i)
print("removing element",i.time)
todel.append(i)
print("*****konec iterace", i.time)
print()
print("to del", todel)
#removing processed from the list
for i in todel:
open_orders.remove(i)
print("cely list po skonceni vseho")
for i in open_orders: print(i.time)
""""
pred iteraci se zavola synchroné
EXECUTE open orders(time)
- pokusi se vytvorit vsechny otevrene ordery do daneho casu (casu dalsi iterace)
- podporuje i volani callbacku a to vcetne pokynu vytvoreneho z pokynu
- tento novy pokyn muze byt i take exekuovan pokud se vcetne roundtripu vejde do daneho casu
pripadne soucasne vytvoreni i exekuci pokynu
"""

View File

@ -0,0 +1,38 @@
from uuid import UUID, uuid4
from alpaca.trading.enums import OrderSide, OrderStatus, TradeEvent, OrderClass, OrderType, TimeInForce
#from utils import AttributeDict
from rich import print
import threading
#import utils
import asyncio
from typing import Any, Optional, List, Union
from datetime import datetime, date
from pydantic import BaseModel
class Order(BaseModel):
id: UUID
submitted_at: datetime
filled_at: Optional[datetime]
symbol: str
qty: Optional[str]
filled_qty: Optional[str]
filled_avg_price: Optional[str]
side: OrderSide
limit_price: Optional[str]
class TradeUpdate(BaseModel):
event: Union[TradeEvent, str]
execution_id: Optional[UUID]
order: Order
timestamp: datetime
position_qty: Optional[float]
price: Optional[float]
qty: Optional[float]
class User(BaseModel):
id: int
name = "Jana"
a = Order(id = uuid4(), submitted_at= datetime.now(), symbol = "BAC", side=OrderSide.BUY)
print(a)

3
testy/archive/config.py Normal file
View File

@ -0,0 +1,3 @@
API_KEY = 'PKGGEWIEYZOVQFDRY70L'
SECRET_KEY = 'O5Kt8X4RLceIOvM98i5LdbalItsX7hVZlbPYHy8Y'
MAX_BATCH_SIZE = 1

View File

@ -0,0 +1,5 @@
import panel as pn
app = pn.Column("DDD")
# app.servable()
# app.append("Nice")
app.show()

View File

@ -0,0 +1,17 @@
import scipy.interpolate as spi
import matplotlib.pyplot as plt
x = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
y = [4, 7, 11, 16, 22, 29, 38, 49, 63, 80]
y_interp = spi.interp1d(x, y)
#find y-value associated with x-value of 13
#print(y_interp(13))
#create plot of x vs. y
#plt.plot(x, y, '-ob')

View File

@ -0,0 +1,31 @@
# narozdil od asyncio a threadingu ma vetsi rezii na vytvoreni
# hodí se pro CPU a GPU narocné úlohy, tnz. treba na strategie, kde kazda strategie = 1 process
import multiprocessing
import logging
logger = multiprocessing.log_to_stderr()
logger.setLevel(logging.INFO)
logger.warning('doomed')
def do_first():
print("Running do_first line 1")
print("Running do_first line 2")
print("Running do_first line 3")
def do_second():
print("Running do_second line 1")
print("Running do_second line 2")
print("Running do_second line 3")
def main():
t1 = multiprocessing.Process(target=do_first)
t2 = multiprocessing.Process(target=do_second)
# Start processes
t1.start(), t2.start()
# Wait processes to complete
t1.join(), t2.join()
if __name__ == "__main__":
main()

145
testy/archive/test.ipynb Normal file
View File

@ -0,0 +1,145 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 97,
"metadata": {},
"outputs": [
{
"ename": "ValidationError",
"evalue": "1 validation error for StockBarsRequest\ntimeframe\n instance of TimeFrame expected (type=type_error.arbitrary_type; expected_arbitrary_type=TimeFrame)",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mValidationError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[97], line 35\u001b[0m\n\u001b[1;32m 30\u001b[0m \u001b[39m#print(time_from)\u001b[39;00m\n\u001b[1;32m 31\u001b[0m \n\u001b[1;32m 32\u001b[0m \u001b[39m# vytvorim request objekt\u001b[39;00m\n\u001b[1;32m 33\u001b[0m \u001b[39m#latestQuoteRequest = StockLatestQuoteRequest(symbol_or_symbols=[\"SPY\", \"GLD\", \"TLT\"])\u001b[39;00m\n\u001b[1;32m 34\u001b[0m stockTradeRequest \u001b[39m=\u001b[39m StockTradesRequest(symbol_or_symbols\u001b[39m=\u001b[39m[\u001b[39m\"\u001b[39m\u001b[39mBAC\u001b[39m\u001b[39m\"\u001b[39m], start\u001b[39m=\u001b[39mtime_from,end\u001b[39m=\u001b[39mtime_to)\n\u001b[0;32m---> 35\u001b[0m stockBarRequest \u001b[39m=\u001b[39m StockBarsRequest(symbol_or_symbols\u001b[39m=\u001b[39;49m[\u001b[39m\"\u001b[39;49m\u001b[39mBAC\u001b[39;49m\u001b[39m\"\u001b[39;49m], start\u001b[39m=\u001b[39;49mtime_from,end\u001b[39m=\u001b[39;49mtime_to, timeframe\u001b[39m=\u001b[39;49m\u001b[39m\"\u001b[39;49m\u001b[39m15s\u001b[39;49m\u001b[39m\"\u001b[39;49m)\n\u001b[1;32m 37\u001b[0m \u001b[39m#zavolam na clientovi metodu s request objektem, vrací se mi Dict[str, Quote] - obj.Quote pro kazdy symbol\u001b[39;00m\n\u001b[1;32m 38\u001b[0m \u001b[39m#latestQuoteObject = stock_client.get_stock_latest_quote(latestQuoteRequest)\u001b[39;00m\n\u001b[1;32m 39\u001b[0m \u001b[39m#tradesResponse = stock_client.get_stock_trades(stockTradeRequest).df\u001b[39;00m\n\u001b[1;32m 40\u001b[0m stocksResponse \u001b[39m=\u001b[39m stock_client\u001b[39m.\u001b[39mget_stock_bars(stockBarRequest)\u001b[39m.\u001b[39mdf\n",
"File \u001b[0;32m~/Documents/Development/python/trading/.venv/lib/python3.11/site-packages/alpaca/data/requests.py:45\u001b[0m, in \u001b[0;36mBaseTimeseriesDataRequest.__init__\u001b[0;34m(self, **data)\u001b[0m\n\u001b[1;32m 37\u001b[0m \u001b[39mif\u001b[39;00m (\n\u001b[1;32m 38\u001b[0m \u001b[39m\"\u001b[39m\u001b[39mend\u001b[39m\u001b[39m\"\u001b[39m \u001b[39min\u001b[39;00m data\n\u001b[1;32m 39\u001b[0m \u001b[39mand\u001b[39;00m data[\u001b[39m\"\u001b[39m\u001b[39mend\u001b[39m\u001b[39m\"\u001b[39m] \u001b[39mis\u001b[39;00m \u001b[39mnot\u001b[39;00m \u001b[39mNone\u001b[39;00m\n\u001b[1;32m 40\u001b[0m \u001b[39mand\u001b[39;00m \u001b[39misinstance\u001b[39m(data[\u001b[39m\"\u001b[39m\u001b[39mend\u001b[39m\u001b[39m\"\u001b[39m], datetime)\n\u001b[1;32m 41\u001b[0m \u001b[39mand\u001b[39;00m data[\u001b[39m\"\u001b[39m\u001b[39mend\u001b[39m\u001b[39m\"\u001b[39m]\u001b[39m.\u001b[39mtzinfo \u001b[39mis\u001b[39;00m \u001b[39mnot\u001b[39;00m \u001b[39mNone\u001b[39;00m\n\u001b[1;32m 42\u001b[0m ):\n\u001b[1;32m 43\u001b[0m data[\u001b[39m\"\u001b[39m\u001b[39mend\u001b[39m\u001b[39m\"\u001b[39m] \u001b[39m=\u001b[39m data[\u001b[39m\"\u001b[39m\u001b[39mend\u001b[39m\u001b[39m\"\u001b[39m]\u001b[39m.\u001b[39mastimezone(pytz\u001b[39m.\u001b[39mutc)\u001b[39m.\u001b[39mreplace(tzinfo\u001b[39m=\u001b[39m\u001b[39mNone\u001b[39;00m)\n\u001b[0;32m---> 45\u001b[0m \u001b[39msuper\u001b[39;49m()\u001b[39m.\u001b[39;49m\u001b[39m__init__\u001b[39;49m(\u001b[39m*\u001b[39;49m\u001b[39m*\u001b[39;49mdata)\n",
"File \u001b[0;32m~/Documents/Development/python/trading/.venv/lib/python3.11/site-packages/pydantic/main.py:342\u001b[0m, in \u001b[0;36mpydantic.main.BaseModel.__init__\u001b[0;34m()\u001b[0m\n",
"\u001b[0;31mValidationError\u001b[0m: 1 validation error for StockBarsRequest\ntimeframe\n instance of TimeFrame expected (type=type_error.arbitrary_type; expected_arbitrary_type=TimeFrame)"
]
}
],
"source": [
"# 2 clients for historical data StockHistoricalDataClient (needs keys), CryptoHistoricalDataClient\n",
"# 2 clients for real time data CryptoDataStream, StockDataStream\n",
"\n",
"\n",
"# naimportuju si daneho clienta\n",
"from alpaca.data.historical import StockHistoricalDataClient, CryptoHistoricalDataClient\n",
"\n",
"#pokdu pouzivam historicke data(tzn. REST) tak si naimportuju dany request object\n",
"from alpaca.data.requests import StockLatestQuoteRequest, StockBarsRequest, StockTradesRequest\n",
"\n",
"#objekty se kterymi pak pracuju (jsou soucasi package výše, tady jen informačně)\n",
"from alpaca.data import Quote, Trade, Snapshot, Bar\n",
"from alpaca.data.models import BarSet, QuoteSet, TradeSet\n",
"\n",
"\n",
"from config import API_KEY, SECRET_KEY\n",
"import datetime\n",
"import pandas as pd\n",
"\n",
"# vytvorim si clienta\n",
"stock_client = StockHistoricalDataClient(API_KEY, SECRET_KEY, raw_data=False)\n",
"\n",
"sloupce=[\"symbol\",\"timestamp\",\"exchange\",\"price\",\"size\",\"id\",\"conditions\",\"tape\"]\n",
"\n",
"# deklarace globalniho df s timeindexem\n",
"#gdf = pd.DataFrame(columns=sloupce, index=pd.to_datetime([]))\n",
"\n",
"time_from = datetime.datetime(2023, 2, 17, 14, 50, 0, 0)\n",
"time_to = datetime.datetime(2023, 2, 17, 14, 55, 1, 0)\n",
"#print(time_from)\n",
"\n",
"# vytvorim request objekt\n",
"#latestQuoteRequest = StockLatestQuoteRequest(symbol_or_symbols=[\"SPY\", \"GLD\", \"TLT\"])\n",
"stockTradeRequest = StockTradesRequest(symbol_or_symbols=[\"BAC\"], start=time_from,end=time_to)\n",
"stockBarRequest = StockBarsRequest(symbol_or_symbols=[\"BAC\"], start=time_from,end=time_to, timeframe=\"15s\")\n",
"\n",
"#zavolam na clientovi metodu s request objektem, vrací se mi Dict[str, Quote] - obj.Quote pro kazdy symbol\n",
"#latestQuoteObject = stock_client.get_stock_latest_quote(latestQuoteRequest)\n",
"#tradesResponse = stock_client.get_stock_trades(stockTradeRequest).df\n",
"stocksResponse = stock_client.get_stock_bars(stockBarRequest).df\n",
"\n",
"#data = [{'t': '2023-02-17T14:50:00.582845696Z', 'x': 'D', 'p': 34.83, 's': 1, 'c': [' ', 'I'], 'i': 71675642337847, 'z': 'A'}, {'t': '2023-02-17T14:50:00.948229632Z', 'x': 'D', 'p': 34.8383, 's': 10, 'c': [' ', 'I'], 'i': 79371872323411, 'z': 'A'}]\n",
"# data = [{ 'conditions': [' ', 'I'],\n",
"# 'exchange': 'D',\n",
"# 'id': 71675642337847,\n",
"# 'price': 34.83,\n",
"# 'size': 1.0,\n",
"# 'symbol': 'BAC',\n",
"# 'tape': 'A',\n",
"# 'timestamp': datetime.datetime(2023, 2, 17, 14, 50, 0, 582845, tzinfo=datetime.timezone.utc)}, { 'conditions': [' ', 'I'],\n",
"# 'exchange': 'D',\n",
"# 'id': 79371872323411,\n",
"# 'price': 34.8383,\n",
"# 'size': 10.0,\n",
"# 'symbol': 'BAC',\n",
"# 'tape': 'A',\n",
"# 'timestamp': datetime.datetime(2023, 2, 17, 14, 50, 0, 948229, tzinfo=datetime.timezone.utc)}, { 'conditions': [' ', 'I'],\n",
"# 'exchange': 'D',\n",
"# 'id': 71675642400306,\n",
"# 'price': 34.835,\n",
"# 'size': 1.0,\n",
"# 'symbol': 'BAC',\n",
"# 'tape': 'A',\n",
"# 'timestamp': datetime.datetime(2023, 2, 17, 14, 50, 1, 870989, tzinfo=datetime.timezone.utc)}, { 'conditions': [' ', 'I'],\n",
"# 'exchange': 'D',\n",
"# 'id': 71675642400308,\n",
"# 'price': 34.84,\n",
"# 'size': 100.0,\n",
"# 'symbol': 'BAC',\n",
"# 'tape': 'A',\n",
"# 'timestamp': datetime.datetime(2023, 2, 17, 14, 55, 0, 88460, tzinfo=datetime.timezone.utc)}]\n",
"# datetime.datetime(2023, 2, 17, 14, 50, 0, 948229, tzinfo=datetime.timezone.utc)\n",
"#data = tradesResponse\n",
"\n",
"#gdf = pd.DataFrame.from_dict(data=data, orient='index')\n",
"#gdf = pd.DataFrame(data)\n",
"\n",
"#gdf = pd.DataFrame(tradesResponse.data[\"BAC\"])\n",
"\n",
"# works with raw data\n",
"#gdf = pd.DataFrame([t for t in tradesResponse[\"BAC\"]], columns=sloupce)\n",
"\n",
"#gdf = tradesResponse.df\n",
"print(stocksResponse)\n",
"# print(tradesResponse)\n",
"#print(tradesResponse[\"BAC\"])\n",
"# print(tradesResponse.data[\"BAC\"])\n",
"\n",
"# positions_df = pd.concat((pd.DataFrame(position).set_index(0) for position in positions),axis=1)\n",
"# positions_df = positions_df.T.apply(pd.to_numeric, errors='ignore').T # convert strings to numeric\n",
"# For orders:\n",
"# orders_df = pd.concat((pd.DataFrame(order).set_index(0) for order in orders),axis=1).T\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.10"
},
"orig_nbformat": 4,
"vscode": {
"interpreter": {
"hash": "9391835cf7167c62e8e53032533e4da7e63c83f818ef5f19912128bc45706236"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}

66
testy/archive/test.py Normal file
View File

@ -0,0 +1,66 @@
from alpaca.data.live import StockDataStream
from alpaca.common.enums import BaseURL
import datetime
import pandas as pd
from alpaca.data.models import Bar, Quote, Trade
import csv
from config import API_KEY, SECRET_KEY
key = 'PKHVMXQA09IVXALL92JR'
secret = 'FmPwQRFIl7jhLRrXee0Ui73zM9NmAf5O4VH2tyAf'
# keys required for stock historical data client
#client = StockHistoricalDataClient(key, secret)
# keys required
client = StockDataStream(api_key=API_KEY,secret_key=SECRET_KEY)
df_glob = pd.DataFrame(columns=['timestamp','symbol', 'exchange','size','price','id','conditions','tape'])
file = open('Trades.txt', 'w')
# async handler
async def quote_data_handler(data):
#global df_glob
#f_loc = pd.DataFrame(data)
#df_glob = df_glob.append(df_loc, ignore_index=True)
# quote data will arrive here
print(data)
ne = str(data) + "\n"
file.write(ne)
#print(data.timestamp,data.symbol, data.price, data.size, data.exchange, data.id, data.conditios,tape)
print("-"*40)
#client.subscribe_updated_bars(quote_data_handler, "BAC")
#client.subscribe_quotes(quote_data_handler, "BAC")
client.subscribe_trades(quote_data_handler, "BAC")
print("pred spustenim run")
try:
client.run()
#print(df)
except Exception as err:
print(f"{type(err).__name__} was raised: {err}")
print("globalni dataframe")
print(df_glob)
file.close()
print(df_glob)
# timestamp symbol exchange size price id conditions tape 0 1
# 0 NaN NaN NaN NaN NaN NaN NaN NaN symbol BAC
# 1 NaN NaN NaN NaN NaN NaN NaN NaN timestamp 2023-02-15 19:47:19.430511+00:00
# 2 NaN NaN NaN NaN NaN NaN NaN NaN exchange V
# 3 NaN NaN NaN NaN NaN NaN NaN NaN price 35.52
# 4 NaN NaN NaN NaN NaN NaN NaN NaN size 50.0
# .. ... ... ... ... ... ... ... ... ... ...
# 59 NaN NaN NaN NaN NaN NaN NaN NaN price 35.51
# 60 NaN NaN NaN NaN NaN NaN NaN NaN size 7.0
# 61 NaN NaN NaN NaN NaN NaN NaN NaN id 56493486924086
# 62 NaN NaN NaN NaN NaN NaN NaN NaN conditions [ , I]
# 63 NaN NaN NaN NaN NaN NaN NaN NaN tape A
order_data_json = request.get_json()
# validate data
MarketOrderRequest(**order_data_json)

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,35 @@
# A condition variable allows one or more threads to wait until they are
# notified by another thread.
import threading
import time
import logging
logging.basicConfig(level=logging.DEBUG,
format='(%(threadName)-9s) %(message)s',)
def consumer(cv):
logging.debug('Consumer thread started ...')
with cv:
logging.debug('Consumer waiting ...')
cv.wait()
logging.debug('Consumer consumed the resource')
def producer(cv):
logging.debug('Producer thread started ...')
with cv:
logging.debug('Making resource available')
logging.debug('Notifying to all consumers')
cv.notify_all()
if __name__ == '__main__':
condition = threading.Condition()
cs1 = threading.Thread(name='consumer1', target=consumer, args=(condition,))
cs2 = threading.Thread(name='consumer2', target=consumer, args=(condition,))
pd = threading.Thread(name='producer', target=producer, args=(condition,))
cs1.start()
time.sleep(2)
cs2.start()
time.sleep(2)
pd.start()

54
testy/archive/thready.py Normal file
View File

@ -0,0 +1,54 @@
# pouziti threadu - narozdil od asyncio - nemame pod tim uplnou kontrolu a ridi to knihovna
# thready jsou výhodne pro naročné IO operace, např. loadery, requestory, scrapery, ukladače atp.
# how to share data between Threads
# 1.Sharing a boolean variable with a threading.Event.
# declare in unset or false state
# event = threading.Event()
# if event.is_set(): # check if set
# event.set() # set the event true
# event.clear() # or false
# 2.Protecting global shared data with a threading.Lock.
# lock = threading.Lock()
# with lock:
# variable = variable + 10
# 3.Sharing data with a queue.Queue. Queue can be shared between threads.
# create a queue
# queue = Queue() #create FIFO
# queue.put(i) #enque
# data = queue.get() #dequeue
# dale je tu condition - takova roura mezi consumerem a producerem
# cond = threading.Condition()
# cond.wait() #consumer waiting
# cond.notifyAll() #producer notifiying consumer, they can continue
# consumer threads wait for the Condition to be set before continuing.
# The producer thread is responsible for setting the condition and notifying the other threads
# that they can continue. Více v sam.test filu.
import threading
def do_first():
print("Running do_first line 1")
print("Running do_first line 2")
print("Running do_first line 3")
def do_second():
print("Running do_second line 1")
print("Running do_second line 2")
print("Running do_second line 3")
def main():
t1 = threading.Thread(target=do_first)
t2 = threading.Thread(target=do_second)
# Start threads
t1.start(), t2.start()
# Wait threads to complete
t1.join(), t2.join()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,74 @@
from uuid import UUID, uuid4
from alpaca.trading.enums import OrderSide, OrderStatus, TradeEvent, OrderClass, OrderType, TimeInForce
#from utils import AttributeDict
from rich import print
from typing import Any, Optional, List, Union
from datetime import datetime, date
from pydantic import BaseModel
from common.model import Order
# to test change iterable (adding items) while iterating
import asyncio
class Notif:
def __init__(self,time):
self.time = time
open_orders: list = []
for i in range(1,10):
open_orders.append(Order(id=uuid4(),
submitted_at = datetime.utcnow(),
qty=1,
order_type=OrderType.MARKET,
symbol = "BAC",
status = OrderStatus.ACCEPTED,
side = OrderSide.BUY))
print("cele pole objektu",open_orders)
# Here, 'reversed' returns a lazy iterator, so it's performant! reversed(l):
#musi fungovat removing stare a pridavani novych
#this list contains all not processed notification, that we try to process during this iteration
#if time is not right we leave the message for next iter
#if time is right we process the message (- note it can trigger additional open_orders, that are added to queue)
async def apenduj():
global open_orders
open_orders.append("cago")
# if notif.time % 2 == 0 and notif.time < 300:
# open_orders.append(Notif(notif.time+50))
todel = []
for i in open_orders:
#print("*******start iterace polozky", i.time)
print(i)
print("removing element",i)
res = asyncio.run(apenduj())
todel.append(i)
print("*****konec iterace", i)
print()
print("to del", todel)
#removing processed from the list
for i in todel:
open_orders.remove(i)
print("cely list po skonceni vseho")
for i in open_orders: print(i.id)
""""
pred iteraci se zavola synchroné
EXECUTE open orders(time)
- pokusi se vytvorit vsechny otevrene ordery do daneho casu (casu dalsi iterace)
- podporuje i volani callbacku a to vcetne pokynu vytvoreneho z pokynu
- tento novy pokyn muze byt i take exekuovan pokud se vcetne roundtripu vejde do daneho casu
pripadne soucasne vytvoreni i exekuci pokynu
"""

70
testy/changeiterable.py Normal file
View File

@ -0,0 +1,70 @@
from uuid import UUID, uuid4
from alpaca.trading.enums import OrderSide, OrderStatus, TradeEvent, OrderClass, OrderType, TimeInForce
#from utils import AttributeDict
from rich import print
from typing import Any, Optional, List, Union
from datetime import datetime, date
from pydantic import BaseModel
from common.model import Order
# to test change iterable (adding items) while iterating
class Notif:
def __init__(self,time):
self.time = time
open_orders: list(Order) = []
for i in range(1,10):
open_orders.append(Order(id=uuid4()),
submitted_at = datetime.utcnow(),
symbol = "BAC",
status = OrderStatus.ACCEPTED,
side = OrderSide.BUY)
print("cele pole objektu",open_orders)
# Here, 'reversed' returns a lazy iterator, so it's performant! reversed(l):
#musi fungovat removing stare a pridavani novych
#this list contains all not processed notification, that we try to process during this iteration
#if time is not right we leave the message for next iter
#if time is right we process the message (- note it can trigger additional open_orders, that are added to queue)
def process_message(notif: Notif):
global open_orders
pass
# if notif.time % 2 == 0 and notif.time < 300:
# open_orders.append(Notif(notif.time+50))
todel = []
for i in open_orders:
#print("*******start iterace polozky", i.time)
process_message(i.id)
print("removing element",i.id)
todel.append(i)
print("*****konec iterace", i.id)
print()
print("to del", todel)
#removing processed from the list
for i in todel:
open_orders.remove(i)
print("cely list po skonceni vseho")
for i in open_orders: print(i.id)
""""
pred iteraci se zavola synchroné
EXECUTE open orders(time)
- pokusi se vytvorit vsechny otevrene ordery do daneho casu (casu dalsi iterace)
- podporuje i volani callbacku a to vcetne pokynu vytvoreneho z pokynu
- tento novy pokyn muze byt i take exekuovan pokud se vcetne roundtripu vejde do daneho casu
pripadne soucasne vytvoreni i exekuci pokynu
"""

File diff suppressed because it is too large Load Diff

151
testy/dash_save_html.py Normal file
View File

@ -0,0 +1,151 @@
# -*- coding: utf-8 -*-
import os
from html.parser import HTMLParser
import dash
import pandas as pd
import plotly.express as px
import requests
from dash import html, dcc, dash_table, Input, Output
def patch_file(file_path: str, content: bytes, extra: dict = None) -> bytes:
if file_path == 'index.html':
index_html_content = content.decode('utf8')
extra_jsons = f'''
var patched_jsons_content={{
{','.join(["'/" + k + "':" + v.decode("utf8") + "" for k, v in extra.items()])}
}};
'''
patched_content = index_html_content.replace(
'<footer>',
f'''
<footer>
<script>
''' + extra_jsons + '''
const origFetch = window.fetch;
window.fetch = function () {
const e = arguments[0]
if (patched_jsons_content.hasOwnProperty(e)) {
return Promise.resolve({
json: () => Promise.resolve(patched_jsons_content[e]),
headers: new Headers({'content-type': 'application/json'}),
status: 200,
});
} else {
return origFetch.apply(this, arguments)
}
}
</script>
'''
).replace(
'href="/',
'href="'
).replace(
'src="/',
'src="'
)
return patched_content.encode('utf8')
else:
return content
def write_file(file_path: str, content: bytes, target_dir='target', ):
target_file_path = os.path.join(target_dir, file_path.lstrip('/').split('?')[0])
target_leaf_dir = os.path.dirname(target_file_path)
os.makedirs(target_leaf_dir, exist_ok=True)
with open(target_file_path, 'wb') as f:
f.write(content)
pass
class ExternalResourceParser(HTMLParser):
def __init__(self):
super().__init__()
self.resources = []
def handle_starttag(self, tag, attrs):
if tag == 'link':
for k, v in attrs:
if k == 'href':
self.resources.append(v)
if tag == 'script':
for k, v in attrs:
if k == 'src':
self.resources.append(v)
def make_static(base_url, target_dir='target'):
index_html_bytes = requests.get(base_url).content
json_paths = ['_dash-layout', '_dash-dependencies', ]
extra_json = {}
for json_path in json_paths:
json_content = requests.get(base_url + json_path).content
extra_json[json_path] = json_content
patched_bytes = patch_file('index.html', index_html_bytes, extra=extra_json)
write_file('index.html', patched_bytes, target_dir)
parser = ExternalResourceParser()
parser.feed(patched_bytes.decode('utf8'))
extra_js = [
'_dash-component-suites/dash/dcc/async-graph.js',
'_dash-component-suites/dash/dcc/async-plotlyjs.js',
'_dash-component-suites/dash/dash_table/async-table.js',
'_dash-component-suites/dash/dash_table/async-highlight.js'
]
for resource_url in parser.resources + extra_js:
resource_url_full = base_url + resource_url
print(f'get {resource_url_full}')
resource_bytes = requests.get(resource_url_full).content
patched_bytes = patch_file(resource_url, resource_bytes)
write_file(resource_url, patched_bytes, target_dir)
def main():
port = 9050
app = dash.Dash(__name__)
df = pd.DataFrame({
"Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"],
"Amount": [4, 1, 2, 2, 4, 5],
"City": ["SF", "SF", "SF", "Montreal", "Montreal", "Montreal"]
})
fig = px.bar(df, x="Fruit", y="Amount", color="City", barmode="group")
app.layout = html.Div(children=[
html.Button('save static', id='save', n_clicks=0),
html.Span('', id='saved'),
html.H1(children='Hello Dash'),
html.Div(children='''
Dash: A web application framework for your data.
'''),
dcc.Graph(
id='example-graph',
figure=fig
),
dash_table.DataTable(
id='table',
columns=[{"name": i, "id": i} for i in df.columns],
data=df.to_dict('records'),
)
])
@app.callback(
Output('saved', 'children'),
Input('save', 'n_clicks'),
)
def save_result(n_clicks):
if n_clicks == 0:
return 'not saved'
else:
make_static(f'http://127.0.0.1:{port}/')
return 'saved'
app.run_server(debug=False, port=port)
if __name__ == '__main__':
main()

38
testy/debugprints.py Normal file
View File

@ -0,0 +1,38 @@
import inspect
import re
import pprint
from rich import print
from datetime import datetime
def d(x, n=None):
frame = inspect.currentframe().f_back
s = inspect.getframeinfo(frame).code_context[0]
print(s)
r = re.search(r"\((.*)\)", s).group(1)
print("{} = {}".format(r,x), n)
def prinfo(*args):
frame = inspect.currentframe().f_back
s = inspect.getframeinfo(frame).code_context[0]
r = re.search(r"\((.*)\)", s).group(1)
print(r)
vnames = r.split(", ")
print(vnames)
for i,(var,val) in enumerate(zip(vnames, args)):
print(f"{var} = {val}")
def p(var, n = None):
if n: print(n, f'{var = }')
else: print(f'{var = }')
a = 34
b= dict(a1=123,b2="cus")
c = "covece"
#p(a)
#d(b, "neco")
p(a)
p(a,"neco")
prinfo(b,c)

70
testy/decorator_test.py Normal file
View File

@ -0,0 +1,70 @@
import inspect
class LiveInterface:
def prepost(f):
def prepost_wrapper(self, *args, **kwargs):
pre_name = 'pre_' + f.__name__
post_name = 'post_' + f.__name__
print(dir(self))
print(self.__repr__)
res = 1
if hasattr(self, pre_name):
res = getattr(self, pre_name) (*args, **kwargs)
if res > 0:
ret = f(self, *args, **kwargs)
if hasattr(self, post_name): getattr(self, post_name)(*args, **kwargs)
return ret
else:
print("plugin vratil zaporné. Skipping")
return res
return prepost_wrapper
def __init__(self) -> None:
pass
@prepost
def buy(self):
print("buy")
##
# class NewInterface(LiveInterface):
# def __init__(self) -> None:
# super().__init__()
class Strategy():
def __init__(self) -> None:
#tady is prepnu na live or bt
self.interface = Strategy.StrategyInterface()
self.neco = 1
#self.interface.buy()
#self.interface = LiveInterface()
#self.interface.buy = self.buy_more
self.interface.buy()
class StrategyInterface(LiveInterface):
def __init__(self) -> None:
super().__init__()
def pre_buy(self):
print("prebuy")
return 3
def post_buy(self):
print("postbuy")
return -2
def main():
a = Strategy()
if __name__ == "__main__":
main()
##

34
testy/gethistorytrades.py Normal file
View File

@ -0,0 +1,34 @@
import os,sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
print(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from alpaca.data.historical import CryptoHistoricalDataClient, StockHistoricalDataClient
from alpaca.data.requests import CryptoLatestTradeRequest, StockLatestTradeRequest, StockLatestBarRequest, StockTradesRequest
from alpaca.data.enums import DataFeed
from config import API_KEY, SECRET_KEY, MAX_BATCH_SIZE
from datetime import datetime, timezone, time, timedelta, date
import pytz
from rich import print
#práce s datumy
zone_NY = pytz.timezone('America/New_York')
parametry = {}
symbol = ["BAC"]
client = StockHistoricalDataClient(API_KEY, SECRET_KEY, raw_data=True)
datetime_object_from = datetime(2023, 3, 16, 9, 30, 0, tzinfo=zone_NY)
datetime_object_to = datetime(2023, 3, 16, 16, 00, 0, tzinfo=zone_NY)
trades_request = StockTradesRequest(symbol_or_symbols=symbol, feed = DataFeed.SIP, start=datetime_object_from, end=datetime_object_to)
all_trades = client.get_stock_trades(trades_request)
#print(all_trades)
print(len(all_trades['BAC']))
# for i in all_trades:
# print(all_trades[i])
if __name__ == "__main__":
# bar will be invoked if this module is being run directly, but not via import!
print("hello")

49
testy/loghandlers.py Normal file
View File

@ -0,0 +1,49 @@
from v2realbot.enums.enums import Mode, Account
from v2realbot.config import get_key
import structlog
from rich import print
from datetime import datetime
from v2realbot.utils.utils import zoneNY
def timestamper(_, __, event_dict):
event_dict["time"] = datetime.now().isoformat()
return event_dict
#structlog.configure(processors=[timestamper, structlog.processors.KeyValueRenderer()])
log = structlog.get_logger()
def neco(arg: int):
log.bind(arg=arg)
log.info("neco funkce")
arg = arg + 2
return arg
def neco2(kwargs):
print("neco 2")
for i in 12:
print(i)
ted = datetime.now().astimezone(zoneNY)
promena = [1,2]
log.bind(ted=ted, promena=promena)
d = dict(a=2,b="33",dalsiklic=4432, pole=[2,3,4])
log.info("beforeprint")
print(d)
d = neco(3)
log.info("udalost")
log.info("incoming",d=d)

View File

@ -0,0 +1,88 @@
from threading import Thread, current_thread
from alpaca.data.live import StockDataStream, CryptoDataStream
from v2realbot.config import API_KEY, SECRET_KEY, MAX_BATCH_SIZE, PAPER
import queue
from alpaca.data.enums import DataFeed
from typing_extensions import Any
import time
from v2realbot.loader.aggregator import TradeAggregator
# class ws_agg() :
# def __init__(self, client, symbol) -> None:
# # Call the Thread class's init function
# Thread.__init__(self)
# self.client = client
# self.symbol = symbol
#object composition
ws_client = CryptoDataStream(API_KEY, SECRET_KEY, raw_data=True, websocket_params={})
_streams = []
def add_stream(self, **data):
#object composition - pomocí append
self._streams.append(data)
async def handler(self, data):
print("handler ve threadu:",current_thread().name)
# podíváme kolik streamů je instancovaných pro tento symbol - v dict[symbol] a spusteni
# pro každý stream zavoláme
print(data)
print("*"*40)
def run(self) :
print(current_thread().name)
print(self._streams)
unique = set()
## for each symbol we subscribe
for i in self._streams:
print(i['symbol'])
#instanciace tradeAggregatoru a uložení do dict[symbol]
#zde
unique.add(i['symbol'])
print(unique)
#subscribe for unique symbols
#
##TODO *PROBLEM* co kdyz chci subscribe stejneho symbolu co uz konzumuje jina strategie. PROBLEM koncepční
##TODO pri skonceni jedne strategie, udelat teardown kroky jako unsubscribe pripadne stop
for i in unique:
WS_Stream.client.subscribe_trades(self.handler, i)
print("subscribed to",i)
#timto se spusti jenom poprve v 1 vlaknu
#ostatni pouze vyuzivaji
if WS_Stream.client._running is False:
print("it is not running, starting by calling RUN")
WS_Stream.client.run()
#tímto se spustí pouze 1.vlakno, nicmene subscribe i pripadny unsubscribe zafunguji
else:
print("it is running, not calling RUN")
# class SymbolStream():
# def __init__(self, symbol) -> None:
# self.symbol = symbol
# s
# class StreamRequest:
# symbol: str
# resolution: int
#clientDataStream = CryptoDataStream(API_KEY, SECRET_KEY, raw_data=True, websocket_params={})
# novy ws stream - vždy jednom vláknu
obj= WS_Stream("jednicka")
obj.add_stream(symbol="BTC/USD",resolution=15)
# novy ws stream - vždy jednom vláknu
obj2= WS_Stream("dvojka")
obj2.add_stream(symbol="ETH/USD",resolution=5)
obj.start()
time.sleep(1)
obj2.start()
# clientDataStream.run()
# clientDataStream2.run()
obj2.join()
obj.join()
print("po startu")

75
testy/pandasinsert.py Normal file
View File

@ -0,0 +1,75 @@
from uuid import UUID, uuid4
from alpaca.trading.enums import OrderSide, OrderStatus, TradeEvent, OrderType
from common.model import TradeUpdate, Order
from rich import print
import threading
import asyncio
from config import BT_DELAYS
from utils.utils import AttributeDict, ltp, zoneNY, trunc
from utils.tlog import tlog
from datetime import datetime
import pandas as pd
import mplfinance as mpf
trade1 = TradeUpdate(order =Order(id=uuid4(),
submitted_at = datetime(2023, 3, 17, 9, 30, 0, 0, tzinfo=zoneNY),
symbol = "BAC",
qty = 1,
status = OrderStatus.ACCEPTED,
order_type = OrderType.LIMIT,
side = OrderSide.BUY,
limit_price=22.4),
event = TradeEvent.FILL,
execution_id = uuid4(),
timestamp = datetime.now(),
position_qty= 2,
price=22.3,
qty = 2,
value = 44.6)
trade2 = TradeUpdate(order =Order(id=uuid4(),
submitted_at = datetime(2023, 3, 17, 9, 34, 0, 0, tzinfo=zoneNY),
symbol = "BAC",
qty = 1,
status = OrderStatus.ACCEPTED,
order_type = OrderType.LIMIT,
side = OrderSide.SELL,
limit_price=22.4),
event = TradeEvent.FILL,
execution_id = uuid4(),
timestamp = datetime.now(),
position_qty= 2,
price=24.3,
qty = 2,
value = 48.6)
trades= [trade1,trade2]
#print(trades)
trade_dict = AttributeDict(timestamp=[],symbol=[],qty=[],price=[],position_qty=[],value=[])
for t in trades:
trade_dict.timestamp.append(t.timestamp)
trade_dict.symbol.append(t.order.symbol)
trade_dict.qty.append(t.qty)
trade_dict.price.append(t.price)
trade_dict.position_qty.append(t.position_qty)
trade_dict.value.append(t.value)
print(trade_dict)
trade_df = pd.DataFrame(trade_dict)
trade_df = trade_df.set_index('timestamp')
mpf.plot(trade_df, # the dataframe containing the OHLC (Open, High, Low and Close) data
type='candle', # use candlesticks
volume=True, # also show the volume
mav=(3,6,9), # use three different moving averages
figratio=(3,1), # set the ratio of the figure
style='yahoo', # choose the yahoo style
title='Bitcoin on Wednesday morning');
print(trade_df)
#pd.DataFrame()
#self.trades.append(trade)

133
testy/pracesdatumem.py Normal file
View File

@ -0,0 +1,133 @@
from alpaca.data.historical import CryptoHistoricalDataClient, StockHistoricalDataClient
from alpaca.data.requests import CryptoLatestTradeRequest, StockLatestTradeRequest, StockLatestBarRequest, StockTradesRequest
from alpaca.data.enums import DataFeed
from v2realbot.config import API_KEY, SECRET_KEY, MAX_BATCH_SIZE
#from v2realbot.utils.utils import zoneNY
from datetime import datetime, timezone, time, timedelta, date
import pytz
from rich import print
from pandas import to_datetime
#práce s datumy
zone_NY = pytz.timezone('America/New_York')
zoneNY=zone_NY
# parametry = {}
# symbol = ["C","BAC"]
# client = StockHistoricalDataClient(API_KEY, SECRET_KEY, raw_data=True)
# datetime_object_from = datetime(2023, 3, 16, 17, 51, 38, tzinfo=timezone.utc)
# datetime_object_to = datetime(2023, 3, 16, 17, 52, 39, tzinfo=timezone.utc)
# trades_request = StockTradesRequest(symbol_or_symbols=symbol, feed = DataFeed.SIP, start=datetime_object_from, end=datetime_object_to)
# all_trades = client.get_stock_trades(trades_request)
# print(len(all_trades))
# for i in all_trades:
# print(all_trades[i])
# timeZ_Ny = pytz.timezone('America/New_York')
# MARKET_OPEN = time(hour=9, minute=30, second=0, tzinfo=timeZ_Ny)
# MARKET_CLOSE = time(hour=16, minute=30, second=0, tzinfo=timeZ_Ny)
# print(MARKET_OPEN)
# print(MARKET_CLOSE)
def is_open_rush(dt: datetime, mins: int = 30):
""""
Returns true if time is within morning rush (open+mins)
"""
dt = dt.astimezone(zoneNY)
business_hours = {
"from": time(hour=9, minute=30),
"to": time(hour=16, minute=0)
}
rushtime = (datetime.combine(date.today(), business_hours["from"]) + timedelta(minutes=mins)).time()
return business_hours["from"] <= dt.time() < rushtime
def is_close_rush(dt: datetime, mins: int = 30):
""""
Returns true if time is within morning rush (open+mins)
"""
dt = dt.astimezone(zoneNY)
business_hours = {
"from": time(hour=9, minute=30),
"to": time(hour=16, minute=0)
}
rushtime = (datetime.combine(date.today(), business_hours["to"]) - timedelta(minutes=mins)).time()
return rushtime <= dt.time() <= business_hours["to"]
now = datetime.now(tz=zone_NY)
now = datetime(2023, 3, 16, 15, 50, 00, tzinfo=zone_NY)
print(now)
print("is closing rush", is_close_rush(now, 0))
""""
TODO toto pridat do utils a pak bud do agregatoru
a nebo do spis offline_loaderu (tam je muzu filtrovat) - pripadne nejake flagy
pak pokracovat v BASE kde jsem skoncil vcera
returns if date is within market open times (no holidays implemented yet)
input is timezone aware datetime
"""
def is_open_hours(dt):
dt = dt.astimezone(pytz.timezone('America/New_York'))
print("ameriko time", dt)
business_hours = {
# monday = 0, tuesday = 1, ... same pattern as date.weekday()
"weekdays": [0, 1, 2, 3, 4],
"from": time(hour=9, minute=30),
"to": time(hour=16, minute=30)
}
holidays = [date(2022, 12, 24), date(2022, 2, 24)]
return dt.weekday() in business_hours["weekdays"] \
and dt.date() not in holidays \
and business_hours["from"] <= dt.time() < business_hours["to"]
now = datetime.now(tz=zone_NY)
now = datetime(2023, 3, 16, 15, 51, 38, tzinfo=zone_NY)
now = datetime(2023, 3, 16, 15, 51, 38, tzinfo=timezone.utc)
print(now)
print("is business hour", is_open_hours(now))
def parse_nanodate(s):
"""
parse date, ignore nanoseconds
sample input: 2020-12-31T16:20:00.000000123Z
--> 123ns will be ignored
"""
print(s[0:26]+s[len(s) - 1]+'+0000')
return datetime.strptime(
s[0:26]+s[len(s) - 1]+'+0000', '%Y-%m-%dT%H:%M:%S.%fZ%z')
a = "2023-03-17T12:56:37.588388864Z"
b = "2023-03-17T12:56:41.332702720Z"
c = "2023-03-17T12:56:41.3327027Z"
d = "2023-03-17T12:01:36.13168Z"
print(to_datetime(d))
print(int(datetime(2023, 3, 17, 9, 30, 0, 0, tzinfo=zone_NY).timestamp()))
print(int(datetime(2023, 3, 17, 16, 00, 0, 0, tzinfo=zone_NY).timestamp()))
# print(a)
# print(parse_nanodate(a).astimezone(tz=zone_NY))
# print(b)
# print(parse_nanodate(b))
# print(c)
# print(parse_nanodate(c))
# print(d)
# print(parse_nanodate(d))

19
testy/printoverride.py Normal file
View File

@ -0,0 +1,19 @@
from rich import print
from icecream import ic
def p(*args, **kwargs):
if ic.enabled:
print(*args, **kwargs)
else:
p("nazdar")
a = "helo"
b = dict(a=123,b="CUS")
c = 123
p(a,b,c,"nazdar")
p("nazdar","covece",a,c)

View File

@ -0,0 +1,233 @@
"""
Zjistovani ceny z listu tradu pomocí bisect left
"""
from datetime import datetime
from bisect import bisect_left
btdata = [(1679081913.290388, 27.8634), (1679081913.68588, 27.865), (1679081913.986394, 27.86), (1679081914.095521, 27.865), (1679081914.396844, 27.8601), (1679081914.601457, 27.865), (1679081914.721968, 27.86), (1679081914.739287, 27.86), (1679081914.739305, 27.865), (1679081914.739314, 27.865), (1679081914.73941, 27.865), (1679081914.739554, 27.86), (1679081914.739569, 27.86), (1679081914.739572, 27.86), (1679081914.739635, 27.86), (1679081914.739644, 27.86), (1679081914.739771, 27.86), (1679081914.74, 27.865), (1679081914.74048, 27.865), (1679081914.740531, 27.865), (1679081914.740691, 27.865), (1679081914.746943, 27.865), (1679081914.779766, 27.86), (1679081914.779769, 27.86), (1679081914.779901, 27.86), (1679081914.779904, 27.865), (1679081914.77991, 27.865), (1679081914.780006, 27.865), (1679081914.780388, 27.865), (1679081914.780415, 27.865), (1679081914.79638, 27.86), (1679081914.79638, 27.86), (1679081914.796383, 27.865), (1679081914.796498, 27.865), (1679081914.796901, 27.865), (1679081914.816074, 27.865), (1679081914.942793, 27.865), (1679081915.424626, 27.8625), (1679081915.863117, 27.865), (1679081915.863255, 27.8675), (1679081915.870084, 27.865), (1679081915.877677, 27.865), (1679081916.015251, 27.865), (1679081916.018716, 27.865), (1679081916.494838, 27.8656), (1679081916.827929, 27.868), (1679081916.870675, 27.8636), (1679081917.140228, 27.87), (1679081917.140763, 27.87), (1679081917.150359, 27.865), (1679081917.753467, 27.865), (1679081917.853001, 27.865), (1679081918.012672, 27.865), (1679081918.736837, 27.865), (1679081918.737011, 27.865), (1679081918.737177, 27.87), (1679081918.742472, 27.87), (1679081918.743335, 27.87), (1679081918.868673, 27.8699), (1679081919.01883, 27.87), (1679081919.018832, 27.87), (1679081919.018835, 27.87), (1679081919.018839, 27.87), (1679081919.018839, 27.87), (1679081919.018857, 27.87), (1679081919.018905, 27.87), (1679081919.018911, 27.87), (1679081919.018911, 27.87), (1679081919.018914, 27.87), (1679081919.018914, 27.87), (1679081919.01892, 27.87), (1679081919.01892, 27.87), (1679081919.018923, 27.87), (1679081919.018929, 27.87), (1679081919.018932, 27.87), (1679081919.018938, 27.87), (1679081919.018941, 27.87), (1679081919.018947, 27.87), (1679081919.01895, 27.87), (1679081919.018956, 27.87), (1679081919.018968, 27.87), (1679081919.018986, 27.87), (1679081919.019074, 27.87), (1679081919.019077, 27.87), (1679081919.019077, 27.87), (1679081919.019079, 27.87), (1679081919.019082, 27.87), (1679081919.019082, 27.87), (1679081919.019095, 27.87), (1679081919.019095, 27.87), (1679081919.0191, 27.87), (1679081919.019103, 27.87), (1679081919.019106, 27.87), (1679081919.019109, 27.87), (1679081919.019112, 27.87), (1679081919.019112, 27.87), (1679081919.019124, 27.87), (1679081919.019127, 27.87), (1679081919.019133, 27.87), (1679081919.019139, 27.87), (1679081919.019323, 27.87), (1679081919.019323, 27.87), (1679081919.019323, 27.87), (1679081919.019323, 27.87), (1679081919.019326, 27.87), (1679081919.019326, 27.87), (1679081919.019936, 27.87), (1679081919.019978, 27.87), (1679081919.020189, 27.87), (1679081919.020264, 27.87), (1679081919.020312, 27.87), (1679081919.020628, 27.87), (1679081919.025445, 27.87), (1679081919.02565, 27.87), (1679081919.066583, 27.87), (1679081919.066953, 27.87), (1679081919.067248, 27.87), (1679081919.067398, 27.875), (1679081919.067672, 27.875), (1679081919.067939, 27.875), (1679081919.067975, 27.875), (1679081919.071849, 27.875), (1679081919.157709, 27.875), (1679081919.184806, 27.875), (1679081919.301574, 27.87), (1679081919.381201, 27.88), (1679081919.381204, 27.88), (1679081919.381237, 27.88), (1679081919.381264, 27.875), (1679081919.381643, 27.88), (1679081919.381649, 27.88), (1679081919.381676, 27.88), (1679081919.381685, 27.88), (1679081919.381697, 27.88), (1679081919.381706, 27.88), (1679081919.381718, 27.88), (1679081919.395142, 27.875), (1679081919.469476, 27.88), (1679081919.570886, 27.88), (1679081919.690577, 27.875), (1679081920.168907, 27.878)]
###
# 1679081919.381264
# 1679081919.381643
# 1679081919.381649
#orizneme pole
index_start = None
index_end = None
range_start = 1679081914.73941
range_end = 1679081917.150359
print("range_start",range_start)
print("range_end",range_end)
a= datetime.now().timestamp()
print("start 1.varianta", a)
# for i in range(len(btdata)):
# print(btdata[i][0])
# print(i)
# if btdata[i][0] <= range_start: index_start = i
# if btdata[i][0] >= range_end:
# index_end = i
# break
print("index_start", index_start)
print("index_end", index_end)
print("oriznuto",btdata[index_start:index_end+1])
new_range =btdata[index_start:index_end+1]
#LIMIT FILL - BUY
submitted_at: float = 1679081914.739644
limit_price: float = 27.865
fill_time = None
bisect_left(submitted_at + 0.020,)
for i in new_range:
#print(i)
##najde prvni nejvetsi čas vetsi nez minfill a majici
## pro LIMITku uděláme nějaký spešl BT_DELAY.LIMIT_OFFSET, aby se nevyplnilo hned jako prvni s touto cenou
## tzn. o kolik se prumerne vyplni limitka pozdeji
if float(i[0]) > float(float(submitted_at) + float(0.020)) and i[1] <= limit_price:
#(1679081919.381649, 27.88)
print(i)
fill_time = i[0]
print("FILL LIMIT BUY at", fill_time, "at",i[1])
break
if not fill_time: print("NO FILL for ", limit_price)
#LIMIT FILL - SELL
for i in new_range:
#print(i)
##najde prvni nejvetsi čas vetsi nez minfill a majici
## pro LIMITku uděláme nějaký spešl BT_DELAY.LIMIT_OFFSET, aby se nevyplnilo hned jako prvni s touto cenou
## tzn. o kolik se prumerne vyplni limitka pozdeji
if float(i[0]) > float(float(submitted_at) + float(0.020)) and i[1] >= limit_price:
#(1679081919.381649, 27.88)
print(i)
fill_time = i[0]
print("FILL LIMIT SELL at", fill_time, "at",i[1])
break
if not fill_time: print("NO FILL for ", limit_price)
#MARKET FILL BUY/SELL:
for i in new_range:
#print(i)
#najde prvni nejvetsi čas vetsi nez minfill
if i[0] > submitted_at + 0.020:
#(1679081919.381649, 27.88)
print(i)
print("FILL MARKET at", i[0], "cena", i[1])
break
b= datetime.now().timestamp()
print("stop 1.varianta", b)
print("rozdil", b-a)
#0.0006699562072753906
#0.0007920265197753906
# (1679081913.290388, 27.8634)
# (1679081913.68588, 27.865)
# (1679081913.986394, 27.86)
# (1679081914.095521, 27.865)
# (1679081914.396844, 27.8601)
# (1679081914.601457, 27.865)
# (1679081914.721968, 27.86)
# (1679081914.739287, 27.86)
# (1679081914.739305, 27.865)
# (1679081914.739314, 27.865)
# (1679081914.73941, 27.865)*
# (1679081914.739554, 27.86)
# (1679081914.739569, 27.86)
# (1679081914.739572, 27.86)
# (1679081914.739635, 27.86)
# (1679081914.739644, 27.86)submit
# (1679081914.739771, 27.86)
# (1679081914.74, 27.865)
# (1679081914.74048, 27.865)
# (1679081914.740531, 27.865)
# (1679081914.740691, 27.865)
# (1679081914.746943, 27.865)
# (1679081914.779766, 27.86)
# (1679081914.779769, 27.86)
# (1679081914.779901, 27.86)
# (1679081914.779904, 27.865)
# (1679081914.77991, 27.865)
# (1679081914.780006, 27.865)
# (1679081914.780388, 27.865)
# (1679081914.780415, 27.865)
# (1679081914.79638, 27.86)
# (1679081914.79638, 27.86)
# (1679081914.796383, 27.865)
# (1679081914.796498, 27.865)
# (1679081914.796901, 27.865)
# (1679081914.816074, 27.865)
# (1679081914.942793, 27.865)
# (1679081915.424626, 27.8625)
# (1679081915.863117, 27.865)
# (1679081915.863255, 27.8675)
# (1679081915.870084, 27.865)
# (1679081915.877677, 27.865)
# (1679081916.015251, 27.865)
# (1679081916.018716, 27.865)
# (1679081916.494838, 27.8656)
# (1679081916.827929, 27.868)
# (1679081916.870675, 27.8636)
# (1679081917.140228, 27.87)
# (1679081917.140763, 27.87)
# (1679081917.150359, 27.865)end
# (1679081917.753467, 27.865)
# (1679081917.853001, 27.865)
# (1679081918.012672, 27.865)
# (1679081918.736837, 27.865)
# (1679081918.737011, 27.865)
# (1679081918.737177, 27.87)
# (1679081918.742472, 27.87)
# (1679081918.743335, 27.87)
# (1679081918.868673, 27.8699)
# (1679081919.01883, 27.87)
# (1679081919.018832, 27.87)
# (1679081919.018835, 27.87)
# (1679081919.018839, 27.87)
# (1679081919.018839, 27.87)
# (1679081919.018857, 27.87)
# (1679081919.018905, 27.87)
# (1679081919.018911, 27.87)
# (1679081919.018911, 27.87)
# (1679081919.018914, 27.87)
# (1679081919.018914, 27.87)
# (1679081919.01892, 27.87)
# (1679081919.01892, 27.87)
# (1679081919.018923, 27.87)
# (1679081919.018929, 27.87)
# (1679081919.018932, 27.87)
# (1679081919.018938, 27.87)
# (1679081919.018941, 27.87)
# (1679081919.018947, 27.87)
# (1679081919.01895, 27.87)
# (1679081919.018956, 27.87)
# (1679081919.018968, 27.87)
# (1679081919.018986, 27.87)
# (1679081919.019074, 27.87)
# (1679081919.019077, 27.87)
# (1679081919.019077, 27.87)
# (1679081919.019079, 27.87)
# (1679081919.019082, 27.87)
# (1679081919.019082, 27.87)
# (1679081919.019095, 27.87)
# (1679081919.019095, 27.87)
# (1679081919.0191, 27.87)
# (1679081919.019103, 27.87)
# (1679081919.019106, 27.87)
# (1679081919.019109, 27.87)
# (1679081919.019112, 27.87)
# (1679081919.019112, 27.87)
# (1679081919.019124, 27.87)
# (1679081919.019127, 27.87)
# (1679081919.019133, 27.87)
# (1679081919.019139, 27.87)
# (1679081919.019323, 27.87)
# (1679081919.019323, 27.87)
# (1679081919.019323, 27.87)
# (1679081919.019323, 27.87)
# (1679081919.019326, 27.87)
# (1679081919.019326, 27.87)
# (1679081919.019936, 27.87)
# (1679081919.019978, 27.87)
# (1679081919.020189, 27.87)
# (1679081919.020264, 27.87)
# (1679081919.020312, 27.87)
# (1679081919.020628, 27.87)
# (1679081919.025445, 27.87)
# (1679081919.02565, 27.87)
# (1679081919.066583, 27.87)
# (1679081919.066953, 27.87)
# (1679081919.067248, 27.87)
# (1679081919.067398, 27.875)
# (1679081919.067672, 27.875)
# (1679081919.067939, 27.875)
# (1679081919.067975, 27.875)
# (1679081919.071849, 27.875)
# (1679081919.157709, 27.875)
# (1679081919.184806, 27.875)
# (1679081919.301574, 27.87)
# (1679081919.381201, 27.88)
# (1679081919.381204, 27.88)
# (1679081919.381237, 27.88)
# (1679081919.381264, 27.875)
# (1679081919.381643, 27.88)
# (1679081919.381649, 27.88)
# (1679081919.381676, 27.88)
# (1679081919.381685, 27.88)
# (1679081919.381697, 27.88)
# (1679081919.381706, 27.88)
# (1679081919.381718, 27.88)
# (1679081919.395142, 27.875)
# (1679081919.469476, 27.88)
# (1679081919.570886, 27.88)
# (1679081919.690577, 27.875)
# (1679081920.168907, 27.878)

View File

@ -0,0 +1,354 @@
"""
standardni pristup zjistovani ceny z listu tradu
"""
from datetime import datetime
import timeit
btdata = [(1679081913.290388, 27.8634), (1679081913.68588, 27.865), (1679081913.986394, 27.86), (1679081914.095521, 27.865), (1679081914.396844, 27.8601), (1679081914.601457, 27.865), (1679081914.721968, 27.86), (1679081914.739287, 27.86), (1679081914.739305, 27.865), (1679081914.739314, 27.865), (1679081914.73941, 27.865), (1679081914.739554, 27.86), (1679081914.739569, 27.86), (1679081914.739572, 27.86), (1679081914.739635, 27.86), (1679081914.739644, 27.86), (1679081914.739771, 27.86), (1679081914.74, 27.865), (1679081914.74048, 27.865), (1679081914.740531, 27.865), (1679081914.740691, 27.865), (1679081914.746943, 27.865), (1679081914.779766, 27.86), (1679081914.779769, 27.86), (1679081914.779901, 27.86), (1679081914.779904, 27.865), (1679081914.77991, 27.865), (1679081914.780006, 27.865), (1679081914.780388, 27.865), (1679081914.780415, 27.865), (1679081914.79638, 27.86), (1679081914.79638, 27.86), (1679081914.796383, 27.865), (1679081914.796498, 27.865), (1679081914.796901, 27.865), (1679081914.816074, 27.865), (1679081914.942793, 27.865), (1679081915.424626, 27.8625), (1679081915.863117, 27.865), (1679081915.863255, 27.8675), (1679081915.870084, 27.865), (1679081915.877677, 27.865), (1679081916.015251, 27.865), (1679081916.018716, 27.865), (1679081916.494838, 27.8656), (1679081916.827929, 27.868), (1679081916.870675, 27.8636), (1679081917.140228, 27.87), (1679081917.140763, 27.87), (1679081917.150359, 27.865), (1679081917.753467, 27.865), (1679081917.853001, 27.865), (1679081918.012672, 27.865), (1679081918.736837, 27.865), (1679081918.737011, 27.865), (1679081918.737177, 27.87), (1679081918.742472, 27.87), (1679081918.743335, 27.87), (1679081918.868673, 27.8699), (1679081919.01883, 27.87), (1679081919.018832, 27.87), (1679081919.018835, 27.87), (1679081919.018839, 27.87), (1679081919.018839, 27.87), (1679081919.018857, 27.87), (1679081919.018905, 27.87), (1679081919.018911, 27.87), (1679081919.018911, 27.87), (1679081919.018914, 27.87), (1679081919.018914, 27.87), (1679081919.01892, 27.87), (1679081919.01892, 27.87), (1679081919.018923, 27.87), (1679081919.018929, 27.87), (1679081919.018932, 27.87), (1679081919.018938, 27.87), (1679081919.018941, 27.87), (1679081919.018947, 27.87), (1679081919.01895, 27.87), (1679081919.018956, 27.87), (1679081919.018968, 27.87), (1679081919.018986, 27.87), (1679081919.019074, 27.87), (1679081919.019077, 27.87), (1679081919.019077, 27.87), (1679081919.019079, 27.87), (1679081919.019082, 27.87), (1679081919.019082, 27.87), (1679081919.019095, 27.87), (1679081919.019095, 27.87), (1679081919.0191, 27.87), (1679081919.019103, 27.87), (1679081919.019106, 27.87), (1679081919.019109, 27.87), (1679081919.019112, 27.87), (1679081919.019112, 27.87), (1679081919.019124, 27.87), (1679081919.019127, 27.87), (1679081919.019133, 27.87), (1679081919.019139, 27.87), (1679081919.019323, 27.87), (1679081919.019323, 27.87), (1679081919.019323, 27.87), (1679081919.019323, 27.87), (1679081919.019326, 27.87), (1679081919.019326, 27.87), (1679081919.019936, 27.87), (1679081919.019978, 27.87), (1679081919.020189, 27.87), (1679081919.020264, 27.87), (1679081919.020312, 27.87), (1679081919.020628, 27.87), (1679081919.025445, 27.87), (1679081919.02565, 27.87), (1679081919.066583, 27.87), (1679081919.066953, 27.87), (1679081919.067248, 27.87), (1679081919.067398, 27.875), (1679081919.067672, 27.875), (1679081919.067939, 27.875), (1679081919.067975, 27.875), (1679081919.071849, 27.875), (1679081919.157709, 27.875), (1679081919.184806, 27.875), (1679081919.301574, 27.87), (1679081919.381201, 27.88), (1679081919.381204, 27.88), (1679081919.381237, 27.88), (1679081919.381264, 27.875), (1679081919.381643, 27.88), (1679081919.381649, 27.88), (1679081919.381676, 27.88), (1679081919.381685, 27.88), (1679081919.381697, 27.88), (1679081919.381706, 27.88), (1679081919.381718, 27.88), (1679081919.395142, 27.875), (1679081919.469476, 27.88), (1679081919.570886, 27.88), (1679081919.690577, 27.875), (1679081920.168907, 27.878)]
from bisect import bisect_left
def get_last_price(time: float, symbol: str = None):
"""""
returns equity price in timestamp. Used for validations later.
TODO: optimalize
"""""
for i in range(len(btdata)):
#print(btdata[i][0])
#print(i)
if btdata[i][0] >= time:
break
return btdata[i-1]
def take_closest(myList, myNumber):
"""
Assumes myList is sorted. Returns first lower value to the number.
"""
pos = bisect_left(myList, (myNumber,))
if pos == 0:
return myList[0]
# if pos == len(myList):
# return myList[-1]
after, afterPrice = myList[pos-1]
return after,afterPrice
print("bisect price")
print(take_closest(btdata, 1679081913.986395))
print("stamdard price")
print(get_last_price(1679081913.986395))
#(1679081919.018929, 27.87), (1679081919.018932, 27.87), (1679081919.018938, 27.87),
# def looper(cislo, btdata):
# for i in range(len(btdata)):
# #print(btdata[i][0])
# #print(i)
# if btdata[i][0] >= cislo:
# index_end = i
# break
# return btdata[i]
# setup = '''
# btdata = [(1679081913.290388, 27.8634), (1679081913.68588, 27.865), (1679081913.986394, 27.86), (1679081914.095521, 27.865), (1679081914.396844, 27.8601), (1679081914.601457, 27.865), (1679081914.721968, 27.86), (1679081914.739287, 27.86), (1679081914.739305, 27.865), (1679081914.739314, 27.865), (1679081914.73941, 27.865), (1679081914.739554, 27.86), (1679081914.739569, 27.86), (1679081914.739572, 27.86), (1679081914.739635, 27.86), (1679081914.739644, 27.86), (1679081914.739771, 27.86), (1679081914.74, 27.865), (1679081914.74048, 27.865), (1679081914.740531, 27.865), (1679081914.740691, 27.865), (1679081914.746943, 27.865), (1679081914.779766, 27.86), (1679081914.779769, 27.86), (1679081914.779901, 27.86), (1679081914.779904, 27.865), (1679081914.77991, 27.865), (1679081914.780006, 27.865), (1679081914.780388, 27.865), (1679081914.780415, 27.865), (1679081914.79638, 27.86), (1679081914.79638, 27.86), (1679081914.796383, 27.865), (1679081914.796498, 27.865), (1679081914.796901, 27.865), (1679081914.816074, 27.865), (1679081914.942793, 27.865), (1679081915.424626, 27.8625), (1679081915.863117, 27.865), (1679081915.863255, 27.8675), (1679081915.870084, 27.865), (1679081915.877677, 27.865), (1679081916.015251, 27.865), (1679081916.018716, 27.865), (1679081916.494838, 27.8656), (1679081916.827929, 27.868), (1679081916.870675, 27.8636), (1679081917.140228, 27.87), (1679081917.140763, 27.87), (1679081917.150359, 27.865), (1679081917.753467, 27.865), (1679081917.853001, 27.865), (1679081918.012672, 27.865), (1679081918.736837, 27.865), (1679081918.737011, 27.865), (1679081918.737177, 27.87), (1679081918.742472, 27.87), (1679081918.743335, 27.87), (1679081918.868673, 27.8699), (1679081919.01883, 27.87), (1679081919.018832, 27.87), (1679081919.018835, 27.87), (1679081919.018839, 27.87), (1679081919.018839, 27.87), (1679081919.018857, 27.87), (1679081919.018905, 27.87), (1679081919.018911, 27.87), (1679081919.018911, 27.87), (1679081919.018914, 27.87), (1679081919.018914, 27.87), (1679081919.01892, 27.87), (1679081919.01892, 27.87), (1679081919.018923, 27.87), (1679081919.018929, 27.87), (1679081919.018932, 27.87), (1679081919.018938, 27.87), (1679081919.018941, 27.87), (1679081919.018947, 27.87), (1679081919.01895, 27.87), (1679081919.018956, 27.87), (1679081919.018968, 27.87), (1679081919.018986, 27.87), (1679081919.019074, 27.87), (1679081919.019077, 27.87), (1679081919.019077, 27.87), (1679081919.019079, 27.87), (1679081919.019082, 27.87), (1679081919.019082, 27.87), (1679081919.019095, 27.87), (1679081919.019095, 27.87), (1679081919.0191, 27.87), (1679081919.019103, 27.87), (1679081919.019106, 27.87), (1679081919.019109, 27.87), (1679081919.019112, 27.87), (1679081919.019112, 27.87), (1679081919.019124, 27.87), (1679081919.019127, 27.87), (1679081919.019133, 27.87), (1679081919.019139, 27.87), (1679081919.019323, 27.87), (1679081919.019323, 27.87), (1679081919.019323, 27.87), (1679081919.019323, 27.87), (1679081919.019326, 27.87), (1679081919.019326, 27.87), (1679081919.019936, 27.87), (1679081919.019978, 27.87), (1679081919.020189, 27.87), (1679081919.020264, 27.87), (1679081919.020312, 27.87), (1679081919.020628, 27.87), (1679081919.025445, 27.87), (1679081919.02565, 27.87), (1679081919.066583, 27.87), (1679081919.066953, 27.87), (1679081919.067248, 27.87), (1679081919.067398, 27.875), (1679081919.067672, 27.875), (1679081919.067939, 27.875), (1679081919.067975, 27.875), (1679081919.071849, 27.875), (1679081919.157709, 27.875), (1679081919.184806, 27.875), (1679081919.301574, 27.87), (1679081919.381201, 27.88), (1679081919.381204, 27.88), (1679081919.381237, 27.88), (1679081919.381264, 27.875), (1679081919.381643, 27.88), (1679081919.381649, 27.88), (1679081919.381676, 27.88), (1679081919.381685, 27.88), (1679081919.381697, 27.88), (1679081919.381706, 27.88), (1679081919.381718, 27.88), (1679081919.395142, 27.875), (1679081919.469476, 27.88), (1679081919.570886, 27.88), (1679081919.690577, 27.875), (1679081920.168907, 27.878)]
# from bisect import bisect_left
# def take_closest(myList, myNumber):
# """
# Assumes myList is sorted. Returns closest value to myNumber.
# If two numbers are equally close, return the smallest number.
# """
# pos = bisect_left(myList, (myNumber,))
# if pos == 0:
# return myList[0]
# if pos == len(myList):
# return myList[-1]
# after, afterPrice = myList[pos]
# return after,afterPrice
# # before, beforePrice = myList[pos - 1]
# # if after - myNumber < myNumber - before:
# # return after,afterPrice
# # else:
# # return before,beforePrice
# #(1679081919.018929, 27.87), (1679081919.018932, 27.87), (1679081919.018938, 27.87),
# def looper(cislo, btdata):
# for i in range(len(btdata)):
# #print(btdata[i][0])
# #print(i)
# if btdata[i][0] >= cislo:
# index_end = i
# break
# return btdata[i]
# '''
# print("bisect")
# print(take_closest(btdata, 1679081919.018939))
# print("standard")
# print(looper(1679081919.018939, btdata))
# print(timeit.timeit('take_closest(btdata, 1679081919.018939)', setup=setup))
# #0.4
# print(timeit.timeit('looper(1679081919.018939, btdata)', setup=setup))
# #2.4
# ###
# # 1679081919.381264
# # 1679081919.381643
# # 1679081919.381649
# #orizneme pole
# """
# btdata obsahuje vsechny aktualni timestampy tradu a jejich cenu.
# 1) pracujeme vzdy na zacatku listu do indexu odpovidajici aktualnimu casu
# 2) zjistime si index a pak iterujeme nad nim
# 3) po skonceni pak tento pracovni kus umazeme
# """
# # def match(time: float):
# a= datetime.now().timestamp()
# print("start 1.varianta", a)
# def get_index_bisect(myList, time):
# """
# Assumes myList is sorted. Returns first biggeer value to the number.
# """
# pos = bisect_left(myList, (time,))
# if pos == 0:
# return myList[0]
# if pos == len(myList):
# return myList[-1]
# return pos
# #after, afterPrice = myList[pos]
# #return after,afterPrice
# def get_index(btdata, time: float):
# index_end = None #
# range_end = time
# print("range_end",range_end)
# for i in range(len(btdata)):
# #print(btdata[i][0])
# #print(i)
# if btdata[i][0] >= range_end:
# index_end = i
# break
# print("index_end", index_end)
# print("oriznuto",btdata[0:index_end+1])
# return index_end
# index_end = get_index(btdata, 1679081919.018939)
# print("get_index", index_end)
# index_end = get_index_bisect(btdata, 1679081919.018939)
# print("get_index_bisect", index_end)
# new_range = btdata[0:index_end+1]
# print("novy rozsah?", len(new_range))
# print("puvodni pole", len(btdata))
# #LIMIT FILL - BUY
# submitted_at: float = 1679081914.739644
# limit_price: float = 27.865
# fill_time = None
# for i in new_range:
# #print(i)
# ##najde prvni nejvetsi čas vetsi nez minfill a majici
# ## pro LIMITku uděláme nějaký spešl BT_DELAY.LIMIT_OFFSET, aby se nevyplnilo hned jako prvni s touto cenou
# ## tzn. o kolik se prumerne vyplni limitka pozdeji
# if float(i[0]) > float(float(submitted_at) + float(0.020)) and i[1] <= limit_price:
# #(1679081919.381649, 27.88)
# print(i)
# fill_time = i[0]
# print("FILL LIMIT BUY at", fill_time, "at",i[1])
# break
# if not fill_time: print("NO FILL for ", limit_price)
# #LIMIT FILL - SELL
# for i in new_range:
# #print(i)
# ##najde prvni nejvetsi čas vetsi nez minfill a majici
# ## pro LIMITku uděláme nějaký spešl BT_DELAY.LIMIT_OFFSET, aby se nevyplnilo hned jako prvni s touto cenou
# ## tzn. o kolik se prumerne vyplni limitka pozdeji
# if float(i[0]) > float(float(submitted_at) + float(0.020)) and i[1] >= limit_price:
# #(1679081919.381649, 27.88)
# print(i)
# fill_time = i[0]
# print("FILL LIMIT SELL at", fill_time, "at",i[1])
# break
# if not fill_time: print("NO FILL for ", limit_price)
# #MARKET FILL BUY/SELL:
# for i in new_range:
# #print(i)
# #najde prvni nejvetsi čas vetsi nez minfill
# if i[0] > submitted_at + 0.020:
# #(1679081919.381649, 27.88)
# print(i)
# print("FILL MARKET at", i[0], "cena", i[1])
# break
# del btdata[0:index_end]
# #0.0006699562072753906
# #0.0007920265197753906
# # (1679081913.290388, 27.8634)
# # (1679081913.68588, 27.865)
# # (1679081913.986394, 27.86)
# # (1679081914.095521, 27.865)
# # (1679081914.396844, 27.8601)
# # (1679081914.601457, 27.865)
# # (1679081914.721968, 27.86)
# # (1679081914.739287, 27.86)
# # (1679081914.739305, 27.865)
# # (1679081914.739314, 27.865)
# # (1679081914.73941, 27.865)*
# # (1679081914.739554, 27.86)
# # (1679081914.739569, 27.86)
# # (1679081914.739572, 27.86)
# # (1679081914.739635, 27.86)
# # (1679081914.739644, 27.86)submit
# # (1679081914.739771, 27.86)
# # (1679081914.74, 27.865)
# # (1679081914.74048, 27.865)
# # (1679081914.740531, 27.865)
# # (1679081914.740691, 27.865)
# # (1679081914.746943, 27.865)
# # (1679081914.779766, 27.86)
# # (1679081914.779769, 27.86)
# # (1679081914.779901, 27.86)
# # (1679081914.779904, 27.865)
# # (1679081914.77991, 27.865)
# # (1679081914.780006, 27.865)
# # (1679081914.780388, 27.865)
# # (1679081914.780415, 27.865)
# # (1679081914.79638, 27.86)
# # (1679081914.79638, 27.86)
# # (1679081914.796383, 27.865)
# # (1679081914.796498, 27.865)
# # (1679081914.796901, 27.865)
# # (1679081914.816074, 27.865)
# # (1679081914.942793, 27.865)
# # (1679081915.424626, 27.8625)
# # (1679081915.863117, 27.865)
# # (1679081915.863255, 27.8675)
# # (1679081915.870084, 27.865)
# # (1679081915.877677, 27.865)
# # (1679081916.015251, 27.865)
# # (1679081916.018716, 27.865)
# # (1679081916.494838, 27.8656)
# # (1679081916.827929, 27.868)
# # (1679081916.870675, 27.8636)
# # (1679081917.140228, 27.87)
# # (1679081917.140763, 27.87)
# # (1679081917.150359, 27.865)end
# # (1679081917.753467, 27.865)
# # (1679081917.853001, 27.865)
# # (1679081918.012672, 27.865)
# # (1679081918.736837, 27.865)
# # (1679081918.737011, 27.865)
# # (1679081918.737177, 27.87)
# # (1679081918.742472, 27.87)
# # (1679081918.743335, 27.87)
# # (1679081918.868673, 27.8699)
# # (1679081919.01883, 27.87)
# # (1679081919.018832, 27.87)
# # (1679081919.018835, 27.87)
# # (1679081919.018839, 27.87)
# # (1679081919.018839, 27.87)
# # (1679081919.018857, 27.87)
# # (1679081919.018905, 27.87)
# # (1679081919.018911, 27.87)
# # (1679081919.018911, 27.87)
# # (1679081919.018914, 27.87)
# # (1679081919.018914, 27.87)
# # (1679081919.01892, 27.87)
# # (1679081919.01892, 27.87)
# # (1679081919.018923, 27.87)
# # (1679081919.018929, 27.87)
# # (1679081919.018932, 27.87)
# # (1679081919.018938, 27.87)
# # (1679081919.018941, 27.87)
# # (1679081919.018947, 27.87)
# # (1679081919.01895, 27.87)
# # (1679081919.018956, 27.87)
# # (1679081919.018968, 27.87)
# # (1679081919.018986, 27.87)
# # (1679081919.019074, 27.87)
# # (1679081919.019077, 27.87)
# # (1679081919.019077, 27.87)
# # (1679081919.019079, 27.87)
# # (1679081919.019082, 27.87)
# # (1679081919.019082, 27.87)
# # (1679081919.019095, 27.87)
# # (1679081919.019095, 27.87)
# # (1679081919.0191, 27.87)
# # (1679081919.019103, 27.87)
# # (1679081919.019106, 27.87)
# # (1679081919.019109, 27.87)
# # (1679081919.019112, 27.87)
# # (1679081919.019112, 27.87)
# # (1679081919.019124, 27.87)
# # (1679081919.019127, 27.87)
# # (1679081919.019133, 27.87)
# # (1679081919.019139, 27.87)
# # (1679081919.019323, 27.87)
# # (1679081919.019323, 27.87)
# # (1679081919.019323, 27.87)
# # (1679081919.019323, 27.87)
# # (1679081919.019326, 27.87)
# # (1679081919.019326, 27.87)
# # (1679081919.019936, 27.87)
# # (1679081919.019978, 27.87)
# # (1679081919.020189, 27.87)
# # (1679081919.020264, 27.87)
# # (1679081919.020312, 27.87)
# # (1679081919.020628, 27.87)
# # (1679081919.025445, 27.87)
# # (1679081919.02565, 27.87)
# # (1679081919.066583, 27.87)
# # (1679081919.066953, 27.87)
# # (1679081919.067248, 27.87)
# # (1679081919.067398, 27.875)
# # (1679081919.067672, 27.875)
# # (1679081919.067939, 27.875)
# # (1679081919.067975, 27.875)
# # (1679081919.071849, 27.875)
# # (1679081919.157709, 27.875)
# # (1679081919.184806, 27.875)
# # (1679081919.301574, 27.87)
# # (1679081919.381201, 27.88)
# # (1679081919.381204, 27.88)
# # (1679081919.381237, 27.88)
# # (1679081919.381264, 27.875)
# # (1679081919.381643, 27.88)
# # (1679081919.381649, 27.88)
# # (1679081919.381676, 27.88)
# # (1679081919.381685, 27.88)
# # (1679081919.381697, 27.88)
# # (1679081919.381706, 27.88)
# # (1679081919.381718, 27.88)
# # (1679081919.395142, 27.875)
# # (1679081919.469476, 27.88)
# # (1679081919.570886, 27.88)
# # (1679081919.690577, 27.875)
# # (1679081920.168907, 27.878)

22
testy/testServices.py Normal file
View File

@ -0,0 +1,22 @@
from v2realbot.utils.utils import AttributeDict, zoneNY, dict_replace_value, Store, parse_toml_string
import os,sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from v2realbot.enums.enums import Mode, Account
from v2realbot.config import WEB_API_KEY
from datetime import datetime
from icecream import install, ic
import os
from rich import print
from threading import current_thread
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import APIKeyHeader
import uvicorn
from uuid import UUID
import controller.services as cs
from v2realbot.common.model import StrategyInstance, RunnerView
d = "[stratvars] maxpozic = 205 chunk = 114 MA = 2 Trend = 3 profit = 0.02 lastbuyindex=-6 pendingbuys={} limitka = 'None' jevylozeno=0 vykladka=5 curve = [0.01, 0.01, 0.01, 0.0, 0.02, 0.02, 0.01,0.01, 0.01,0.03, 0.01, 0.01, 0.01,0.04, 0.01,0.01, 0.01,0.05, 0.01,0.01, 0.01,0.01, 0.06,0.01, 0.01,0.01, 0.01] blockbuy = 0 ticks2reset = 0.04"
d='[stratvars]\r\n maxpozic = 200\r\n chunk = 111\r\n MA = 2\r\n Trend = 3\r\n profit = 0.02\r\n lastbuyindex=-6\r\n pendingbuys={}\r\n limitka = "None"\r\n jevylozeno=0\r\n vykladka=5\r\n curve = [0.01, 0.01, 0.01, 0.0, 0.02, 0.02, 0.01,0.01, 0.01,0.03, 0.01, 0.01, 0.01,0.04, 0.01,0.01, 0.01,0.05, 0.01,0.01, 0.01,0.01, 0.06,0.01, 0.01,0.01, 0.01]\r\n blockbuy = 0\r\n ticks2reset = 0.04'
print(d)
a,b = parse_toml_string(d)
print(a,b)

57
testy/testStore Normal file
View File

@ -0,0 +1,57 @@
import os,sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import pickle
from v2realbot.common.model import StrategyInstance
from typing import List, Self
#class to persist
class Store:
def __init__(self) -> None:
self.silist : List[StrategyInstance] = None
self.db_file ="cache/strategyinstances.cache"
if os.path.exists(self.db_file):
with open (self.db_file, 'rb') as fp:
self.silist = pickle.load(fp)
def save(self):
with open(self.db_file, 'wb') as fp:
pickle.dump(self.silist, fp)
db = Store()
print(db.silist)
db.silist.append(StrategyInstance(
id2=1,
name="DD",
symbol="DD",
class_name="DD",
script="DD",
open_rush=1,
close_rush=1,
stratvars_conf="DD",
add_data_conf="DD"))
print(db.silist)
db.silist = []
print(len(db.silist))
db.save()
# class Neco:
# def __init__(self) -> None:
# pass
# a = 1
# b = 2
# def toJson(self):
# return json.dumps(self, default=lambda o: o.__dict__)
# db.append(Neco.a)
# db.append(Neco.b)
# db.append(Neco)
# print(Neco)

12
testy/testTIMIT Normal file
View File

@ -0,0 +1,12 @@
import timeit
setup = '''
import msgpack
import json
from copy import deepcopy
data = {'name':'John Doe','ranks':{'sports':13,'edu':34,'arts':45},'grade':5}'''
print(timeit.timeit('deepcopy(data)', setup=setup))
# 12.0860249996
print(timeit.timeit('json.loads(json.dumps(data))', setup=setup))
# 9.07182312012
print(timeit.timeit('msgpack.unpackb(msgpack.packb(data))', setup=setup))
# 1.42743492126

View File

@ -0,0 +1,86 @@
from datetime import date, timedelta
from alpaca.data.historical import CryptoHistoricalDataClient, StockHistoricalDataClient
from alpaca.data.requests import CryptoLatestTradeRequest, StockLatestTradeRequest, StockLatestBarRequest, StockTradesRequest
from alpaca.data.enums import DataFeed
from alpaca.trading.requests import GetCalendarRequest
from alpaca.trading.client import TradingClient
from alpaca.trading.models import Calendar
from config import API_KEY, SECRET_KEY, MAX_BATCH_SIZE
from datetime import datetime, timezone, time, timedelta, date
import pytz
from rich import print
import os
from icecream import install, ic
install()
import os
# print('Get current working directory : ', os.getcwd())
# print('File name : ', os.path.basename(__file__))
# print('Directory Name: ', os.path.dirname(__file__))
#práce s datumy
zone_NY = pytz.timezone('America/New_York')
symbol = "BAC"
client = TradingClient(API_KEY, SECRET_KEY, raw_data=False)
datetime_object_from = datetime(2023, 3, 16, 17, 51, 38, tzinfo=timezone.utc)
datetime_object_to = datetime(2023, 3, 22, 17, 52, 39, tzinfo=timezone.utc)
calendar_request = GetCalendarRequest(start=datetime_object_from,end=datetime_object_to)
cal_dates = client.get_calendar(calendar_request)
#curr_dir = os.path.dirname(__file__)
#backtesting a obecne prace startegie s dnem
#zatim podporime pouze main session
#backtest
#- market open trade - Q
#- market close trade - M
#minimalni jednotka pro CACHE je 1 den - a to jen marketopen to marketclose (extended hours not supported yet)
for day in cal_dates:
print("Processing DAY", day.date)
print(day.date)
print(day.open)
print(day.close)
#get file name
daily_file = str(symbol) + '-' + str(int(day.open.timestamp())) + '-' + str(int(day.close.timestamp())) + '.cache'
print(daily_file)
if os.path.exists(daily_file):
pass
##denní file existuje
#loadujeme ze souboru
#pokud je start_time < trade < end_time
#odesíláme do queue
#jinak pass
else:
ic("cache not exists")
#denni file není - loadujeme den z Alpacy
#ukládáme do cache s daily_file jako název
#pokud jde o dnešní den a nebyl konec trhu tak cache neukládáme
if datetime.now() < day.close:
print("not saving the cache, market still open today")
ic(datetime.now())
ic(day.close)
else:
pass
#save to daily cache file curr_dir+'/'+daily_file
#pokud je start_time < trade < end_time
#odesíláme do queue
#jinak ne
print("Processing DAY END",day.date)
# start_date = date(2008, 8, 15)
# end_date = date(2008, 9, 15) # perhaps date.now()
# ##get number of days between days
# delta = end_date - start_date # returns timedelta
# for i in range(delta.days + 1):
# day = start_date + timedelta(days=i)
# print(day)
# #pro kazde datum volame get cala - jestli byl trader date

165
testy/threadclassestest.py Normal file
View File

@ -0,0 +1,165 @@
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
import queue
from alpaca.data.enums import DataFeed
from typing_extensions import Any
import time
from v2realbot.loader.aggregator import TradeAggregator2Queue
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Order
# class ws_agg() :
# def __init__(self, client, symbol) -> None:
# # Call the Thread class's init function
# Thread.__init__(self)
# self.client = client
# self.symbol = symbol
#object composition
"""""
vlakno je zde pro asynchronni zapnuti klienta,
vlakno je vzdy pouze jedno, nicmene instancovani teto tridy je kvuli stejnemu chovani
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={})
_streams = []
lock = threading.Lock()
def __init__(self, name) -> None:
# Call the Thread class's init function
Thread.__init__(self, name=name)
#promenna bude obsahovat seznam streamů
name = name
def symbol_exists(self, symbol):
for i in WS_Stream._streams:
if i.symbol == symbol:
return True
return False
def add_stream(self, obj):
WS_Stream._streams.append(obj)
if WS_Stream.client._running is False:
print("websocket zatim nebezi, pridavame do pole")
#do promenne tridy se zapise agregator
else:
print("websokcet bezi - pouze subscribujeme")
WS_Stream.client.subscribe_trades(self.handler, obj.symbol)
print("muze se vratit uz subscribnuto, coz je ok")
def remove_stream(self, obj):
#delete added stream
try:
WS_Stream._streams.remove(obj)
except ValueError:
print("value not found in _streams")
return
#if it is the last item at all, stop the client from running
if len( WS_Stream._streams) == 0:
print("removed last item from WS, stopping the client")
WS_Stream.client.stop()
return
if not self.symbol_exists(obj.symbol):
WS_Stream.client.unsubscribe_trades(obj.symbol)
print("symbol no longer used, unsubscribed from ", obj.symbol)
@classmethod
async def handler(cls, data):
print("handler ve threadu:",current_thread().name)
# podíváme kolik streamů je instancovaných pro tento symbol - v dict[symbol] a spusteni
# pro každý stream zavoláme
print(data)
print("*"*40)
def run(self):
print(self.name, "AKtualni vlakno")
if(len(self._streams)==0):
print(self.name, "no streams. no run")
return
#print(self._streams)
unique = set()
## for each symbol we subscribe
for i in self._streams:
#print(self.name, i.symbol)
#instanciace tradeAggregatoru a uložení do dict[symbol]
#zde
unique.add(i.symbol)
#print(unique)
#subscribe for unique symbols
#
##TODO *PROBLEM* co kdyz chci subscribe stejneho symbolu co uz konzumuje jina strategie. PROBLEM koncepční
##TODO pri skonceni jedne strategie, udelat teardown kroky jako unsubscribe pripadne stop
for i in unique:
WS_Stream.client.subscribe_trades(self.handler, i)
print(self.name, "subscribed to",i)
#timto se spusti jenom poprve v 1 vlaknu
#ostatni pouze vyuzivaji
if WS_Stream.client._running is False:
print(self.name, "it is not running, starting by calling RUN")
WS_Stream.client.run()
#tímto se spustí pouze 1.vlakno, nicmene subscribe i pripadny unsubscribe zafunguji
else:
print(self.name, "it is running, not calling RUN")
# class SymbolStream():
# def __init__(self, symbol) -> None:
# self.symbol = symbol
# s
# class StreamRequest:
# symbol: str
# resolution: int
#clientDataStream = CryptoDataStream(API_KEY, SECRET_KEY, raw_data=True, websocket_params={})
# 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)
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)
obj2.add_stream(stream2)
print("2", WS_Stream._streams)
obj.start()
print("po startu prvniho")
print(WS_Stream._streams)
time.sleep(1)
obj2.start()
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)
obj3.add_stream(stream3)
obj3.start()
print(WS_Stream._streams)
print("po zapnuti trojky")
time.sleep(5)
print("cekame na skonceni")
print("celkem enumerate", threading.enumerate())
time.sleep(2)
print("rusim jednicku")
obj.remove_stream(stream1)
print("po ruseni")
time.sleep(2)
print("rusim dvojku")
obj2.remove_stream(stream2)
print("po ruseni")
time.sleep(2)
print("rusim trojku")
obj3.remove_stream(stream3)
obj2.join()
obj.join()

111
testy/websocketFastApi.py Normal file
View File

@ -0,0 +1,111 @@
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Depends, HTTPException, status, WebSocketException, Cookie, Query
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.security import HTTPBasic, HTTPBasicCredentials
import secrets
from typing import Annotated
import os
import uvicorn
import json
from datetime import datetime
from v2realbot.utils.utils import zoneNY
app = FastAPI()
root = os.path.dirname(os.path.abspath(__file__))
app.mount("/static", StaticFiles(directory=os.path.join(root, 'static')), name="static")
html = """
<!DOCTYPE html>
<html>
<head>
<title>Chat</title>
<script type="text/javascript" src="https://unpkg.com/lightweight-charts/dist/lightweight-charts.standalone.production.js"
></script>
</head>
<body>
<h1>Realtime chart</h1>
<h2>Your ID: <span id="ws-id"></span></h2>
<h3>Status: <span id="status">Not connected</span></h3>
<form action="" onsubmit="sendMessage(event)">
<label>Runner ID: <input type="text" id="runnerId" autocomplete="off" value="foo"/></label>
<label>Token: <input type="text" id="token" autocomplete="off" value="some-key-token"/></label>
<button onclick="connect(event)" id="bt-conn">Connect</button>
<button onclick="disconnect(event)" id="bt-disc" style="display: None">Disconnect</button>
<hr>
<label>Message: <input type="text" id="messageText" autocomplete="off"/></label>
<button>Send</button>
</form>
<ul id='messages'>
</ul>
<div id="chart"></div>
<div id="conteiner"></div>
<script src="/static/js/mywebsocket.js"></script>
<script src="/static/js/mychart.js"></script>
</body>
</html>
"""
security = HTTPBasic()
async def get_cookie_or_token(
websocket: WebSocket,
session: Annotated[str | None, Cookie()] = None,
token: Annotated[str | None, Query()] = None,
):
if session is None and token is None:
raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION)
return session or token
def get_current_username(
credentials: Annotated[HTTPBasicCredentials, Depends(security)]
):
if not (credentials.username == "david") or not (credentials.password == "david"):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect email or password",
headers={"WWW-Authenticate": "Basic"},
)
@app.get("/")
async def get(username: Annotated[str, Depends(get_current_username)]):
return HTMLResponse(html)
@app.websocket("/runners/{runner_id}/ws")
async def websocket_endpoint(
*,
websocket: WebSocket,
runner_id: str,
q: int | None = None,
cookie_or_token: Annotated[str, Depends(get_cookie_or_token)],
):
await websocket.accept()
try:
while True:
data = await websocket.receive_text()
await websocket.send_text(
f"Session cookie or query token value is: {cookie_or_token}"
)
if q is not None:
await websocket.send_text(f"Query parameter q is: {q}")
data = {'high': 195,
'low': 180,
'volume': 123,
'close': 185,
'hlcc4': 123,
'open': 190,
'time': "2019-05-25",
'trades':123,
'resolution':123,
'confirmed': 123,
'vwap': 123,
'updated': 123,
'index': 123}
await websocket.send_text(json.dumps(data))
except WebSocketDisconnect:
print("CLIENT DISCONNECTED for", runner_id)
if __name__ == "__main__":
uvicorn.run("__main__:app", host="0.0.0.0", port=8000, reload=False)

View File

@ -0,0 +1,111 @@
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Depends, HTTPException, status
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.security import HTTPBasic, HTTPBasicCredentials
import secrets
from typing import Annotated
import os
import uvicorn
import json
from datetime import datetime
from v2realbot.utils.utils import zoneNY
app = FastAPI()
root = os.path.dirname(os.path.abspath(__file__))
app.mount("/static", StaticFiles(directory=os.path.join(root, 'static')), name="static")
html = """
<!DOCTYPE html>
<html>
<head>
<title>Chat</title>
<script type="text/javascript" src="https://unpkg.com/lightweight-charts/dist/lightweight-charts.standalone.production.js"
></script>
</head>
<body>
<h1>Realtime chart</h1>
<h2>Your ID: <span id="ws-id"></span></h2>
<form action="" onsubmit="sendMessage(event)">
<input type="text" id="messageText" autocomplete="off"/>
<button>Send</button>
</form>
<ul id='messages'>
</ul>
<div id="chart"></div>
<div id="conteiner"></div>
<script src="/static/js/mywebsocket.js"></script>
<script src="/static/js/mychart.js"></script>
</body>
</html>
"""
class ConnectionManager:
def __init__(self):
self.active_connections: list[WebSocket] = []
async def connect(self, websocket: WebSocket):
await websocket.accept()
self.active_connections.append(websocket)
def disconnect(self, websocket: WebSocket):
self.active_connections.remove(websocket)
async def send_personal_message(self, message: str, websocket: WebSocket):
await websocket.send_text(message)
async def broadcast(self, message: str):
for connection in self.active_connections:
await connection.send_text(message)
manager = ConnectionManager()
security = HTTPBasic()
def get_current_username(
credentials: Annotated[HTTPBasicCredentials, Depends(security)]
):
if not (credentials.username == "david") or not (credentials.password == "david"):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect email or password",
headers={"WWW-Authenticate": "Basic"},
)
@app.get("/")
async def get(username: Annotated[str, Depends(get_current_username)]):
return HTMLResponse(html)
@app.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: int):
await manager.connect(websocket)
try:
while True:
data = await websocket.receive_text()
data = {'high': 195,
'low': 180,
'volume': 123,
'close': 185,
'hlcc4': 123,
'open': 190,
'time': "2019-05-25",
'trades':123,
'resolution':123,
'confirmed': 123,
'vwap': 123,
'updated': 123,
'index': 123}
# data = {'high': 123,
# 'low': 123,
# 'close': 123,
# 'open': 123,
# 'time': "2019-05-25"}
await manager.send_personal_message(json.dumps(data), websocket)
#await manager.broadcast(f"Client #{client_id} says: {data}")
except WebSocketDisconnect:
manager.disconnect(websocket)
await manager.broadcast(f"Client #{client_id} left the chat")
if __name__ == "__main__":
uvicorn.run("__main__:app", host="0.0.0.0", port=8000, reload=False)

View File

@ -0,0 +1,90 @@
from strategy.base import Strategy, StrategyState
from strategy.strategyOrderLimit import StrategyOrderLimit
from enums import RecordType, StartBarAlign, Mode
from config import API_KEY, SECRET_KEY, MAX_BATCH_SIZE, PAPER
from indicators import ema
from rich import print
from utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY
from datetime import datetime
from icecream import install, ic
install()
ic.configureOutput(includeContext=True)
#ic.disable()
""""
Simple strategie pro test backtesting
"""
def next(data, state: StrategyState):
print(10*"*","NEXT START",10*"*")
ic(state.avgp, state.positions)
ic(state.vars.limitka)
ic(state.vars.lastbuyindex)
ic(data)
#print("last trade price")
#print(state.interface.get_last_price("BAC"))
#print(state.vars.novaprom)
#print("trades history", state.trades)
#print("bar history", state.bars)
#print("ltp", ltp.price["BAC"], ltp.time["BAC"])
#TODO indikátory ukládat do vlastní historie - tu pak automaticky zobrazuje backtester graf
#TODO ema = state.indicators.ema a pouzivat nize ema, zjistit jestli bude fungovat
try:
state.indicators.ema = ema(state.bars.hlcc4, state.vars.MA) #state.bars.vwap
#trochu prasarna, EMAcko trunc na 3 mista - kdyz se osvedci, tak udelat efektivne
state.indicators.ema = [trunc(i,3) for i in state.indicators.ema]
ic(state.vars.MA, state.vars.Trend, state.indicators.ema[-5:])
except Exception as e:
print("No data for MA yet", str(e))
print("is falling",isfalling(state.indicators.ema,state.vars.Trend))
print("is rising",isrising(state.indicators.ema,state.vars.Trend))
#ZDE JSEM SKONCIL
#nejprve zacit s BARy
#TODO vyzkoušet limit buy - vetsina z nakupu by se dala koupit o cent dva mene
#proto dodělat LTP pro BT, neco jako get_last_price(self.state.time)
##TODO vyzkouset hlidat si sell objednavku sam na zaklade tradu
# v pripade ze to jde nahoru(is rising - nebo jiny indikator) tak neprodavat
#vyuzit CBARy k tomuto .....
#triggerovat buy treba po polovine CBARu, kdyz se cena bude rovnat nebo bude nizsi nez low
#a hned na to (po potvrzeni) hlidat sell +0.01 nebo kdyz roste nechat rust.vyzkouset na LIVE
if isfalling(state.indicators.ema,state.vars.Trend) and data['index'] > state.vars.lastbuyindex+state.vars.Trend: #and state.blockbuy == 0
print("BUY MARKET")
ic(data['updated'])
ic(state.time)
state.buy_l()
print(10*"*","NEXT STOP",10*"*")
def init(state: StrategyState):
#place to declare new vars
print("INIT v main",state.name)
state.vars['novaprom'] = 4
state.indicators['ema'] = []
def main():
stratvars = AttributeDict(maxpozic = 2400, chunk = 400, MA = 6, Trend = 7, profit = 0.03, lastbuyindex=-6, pendingbuys={},limitka = None)
s = StrategyOrderLimit(name = "BackTEST", symbol = "KO", next=next, init=init, stratvars=stratvars, debug=False)
s.set_mode(mode = Mode.BT,
start = datetime(2023, 2, 23, 9, 30, 0, 0, tzinfo=zoneNY),
end = datetime(2023, 2, 23, 16, 00, 0, 0, tzinfo=zoneNY),
cash=100000)
#na sekundovem baru nezaokrouhlovat MAcko
s.add_data(symbol="KO",rectype=RecordType.BAR,timeframe=30,filters=None,update_ltp=True,align=StartBarAlign.RANDOM,mintick=0)
#s.add_data(symbol="C",rectype=RecordType.BAR,timeframe=1,filters=None,update_ltp=True,align=StartBarAlign.ROUND,mintick=0)
s.start()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,99 @@
# import os,sys
# sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from v2realbot.strategy.base import Strategy, StrategyState
from v2realbot.strategy.StrategyOrderLimitKOKA import StrategyOrderLimitKOKA
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode
from v2realbot.indicators.indicators import ema
from rich import print
from v2realbot.utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY
from datetime import datetime
from icecream import install, ic
import os
install()
ic.configureOutput(includeContext=True)
#ic.disable()
""""
Simple strategie LIMIT buy a lIMIT SELL working ok
DOkupovaci strategie, nakupuje dalsi pozice až po dalším signálu.
POZOR nekontroluje se maximální pozice - tzn. nejvic se vycerpalo 290, ale prezila kazdy den.
Dobrá defenzivní pri nastaveni
30s maxpozic = 290,chunk = 10,MA = 6,Trend = 6,profit = 0.02,
"""
stratvars = AttributeDict(maxpozic = 250,
chunk = 10,
MA = 6,
Trend = 6,
profit = 0.02,
lastbuyindex=-6,
pendingbuys={},
limitka = None)
def next(data, state: StrategyState):
print(10*"*","NEXT START",10*"*")
ic(state.avgp, state.positions)
ic(state.vars.limitka)
ic(state.vars.lastbuyindex)
ic(data)
#print("last trade price")
#print(state.interface.get_last_price("BAC"))
#print(state.vars.novaprom)
#print("trades history", state.trades)
#print("bar history", state.bars)
#print("ltp", ltp.price["BAC"], ltp.time["BAC"])
#TODO indikátory ukládat do vlastní historie - tu pak automaticky zobrazuje backtester graf
#TODO ema = state.indicators.ema a pouzivat nize ema, zjistit jestli bude fungovat
try:
state.indicators.ema = ema(state.bars.hlcc4, state.vars.MA) #state.bars.vwap
#trochu prasarna, EMAcko trunc na 3 mista - kdyz se osvedci, tak udelat efektivne
state.indicators.ema = [trunc(i,3) for i in state.indicators.ema]
ic(state.vars.MA, state.vars.Trend, state.indicators.ema[-5:])
except Exception as e:
print("No data for MA yet", str(e))
print("is falling",isfalling(state.indicators.ema,state.vars.Trend))
print("is rising",isrising(state.indicators.ema,state.vars.Trend))
#ZDE JSEM SKONCIL
#nejprve zacit s BARy
#TODO vyzkoušet limit buy - vetsina z nakupu by se dala koupit o cent dva mene
#proto dodělat LTP pro BT, neco jako get_last_price(self.state.time)
if isfalling(state.indicators.ema,state.vars.Trend) and data['index'] > state.vars.lastbuyindex+state.vars.Trend: #and state.blockbuy == 0
print("BUY MARKET")
ic(data['updated'])
ic(state.time)
state.buy_l()
print(10*"*","NEXT STOP",10*"*")
def init(state: StrategyState):
#place to declare new vars
print("INIT v main",state.name)
state.vars['novaprom'] = 4
state.indicators['ema'] = []
def main():
name = os.path.basename(__file__)
s = StrategyOrderLimitKOKA(name = name, symbol = "BAC", next=next, init=init, stratvars=stratvars, open_rush=30, close_rush=0)
s.set_mode(mode = Mode.PAPER,
debug = False,
start = datetime(2023, 3, 6, 9, 30, 0, 0, tzinfo=zoneNY),
end = datetime(2023, 3, 9, 16, 0, 0, 0, tzinfo=zoneNY),
cash=100000)
#na sekundovem baru nezaokrouhlovat MAcko
s.add_data(symbol="BAC",rectype=RecordType.BAR,timeframe=30,filters=None,update_ltp=True,align=StartBarAlign.ROUND,mintick=0)
#s.add_data(symbol="C",rectype=RecordType.BAR,timeframe=1,filters=None,update_ltp=True,align=StartBarAlign.ROUND,mintick=0)
s.start()
print("zastavujeme")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,243 @@
import os,sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from v2realbot.strategy.base import StrategyState
from v2realbot.strategy.StrategyOrderLimitVykladaci import StrategyOrderLimitVykladaci
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account
from v2realbot.indicators.indicators import ema
from v2realbot.utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY, price2dec, dict_replace_value
from datetime import datetime
from icecream import install, ic
from rich import print
from threading import Event
import asyncio
import os
import tomli
install()
ic.configureOutput(includeContext=True)
#ic.disable()
print(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
""""
Vykladaci strategie refactored z původního engine
Params:
(maxpozic = 200, chunk = 50, MA = 6, Trend = 6, profit = 0.02, lastbuyindex=-6, pendingbuys={},limitka = None, jevylozeno=0, ticks2reset = 0.04, blockbuy=0)
Více nakupuje oproti Dokupovaci. Tady vylozime a nakupujeme 5 pozic hned. Pri dokupovaci se dokupuje, az na zaklade dalsich triggeru.
Do budoucna vice ridit nakupy pri klesani - napr. vyložení jen 2-3 pozic a další dokupy až po triggeru.
#
"""
stratvars = AttributeDict(maxpozic = 250,
chunk = 10,
MA = 3,
Trend = 3,
profit = 0.02,
lastbuyindex=-6,
pendingbuys={},
limitka = None,
jevylozeno=0,
vykladka=5,
curve = [0.01, 0.01, 0.01, 0, 0.02, 0.02, 0.01,0.01, 0.01,0.03, 0.01, 0.01, 0.01,0.04, 0.01,0.01, 0.01,0.05, 0.01,0.01, 0.01,0.01, 0.06,0.01, 0.01,0.01, 0.01],
blockbuy = 0,
ticks2reset = 0.04)
##toto rozparsovat a strategii spustit stejne jako v main
toml_string = """
[[strategies]]
name = "V1 na BAC"
symbol = "BAC"
script = "ENTRY_backtest_strategyVykladaci"
class = "StrategyOrderLimitVykladaci"
open_rush = 0
close_rush = 0
[strategies.stratvars]
maxpozic = 200
chunk = 10
MA = 6
Trend = 5
profit = 0.02
lastbuyindex=-6
pendingbuys={}
limitka = "None"
jevylozeno=0
vykladka=5
curve = [0.01, 0.01, 0.01,0.01, 0.02, 0.01,0.01, 0.01,0.03, 0.01, 0.01, 0.01,0.04, 0.01,0.01, 0.01,0.05, 0.01,0.01, 0.01,0.01, 0.06,0.01, 0.01,0.01, 0.01]
blockbuy = 0
ticks2reset = 0.04
[[strategies.add_data]]
symbol="BAC"
rectype="bar"
timeframe=5
update_ltp=true
align="round"
mintick=0
minsize=100
exthours=false
"""
def next(data, state: StrategyState):
print(10*"*","NEXT START",10*"*")
ic(state.avgp, state.positions)
ic(state.vars)
ic(data)
#mozna presunout o level vys
def vyloz():
##prvni se vyklada na aktualni cenu, další jdou podle krivky, nula v krivce zvyšuje množství pro následující iteraci
#curve = [0.01, 0.01, 0, 0, 0.01, 0, 0, 0, 0.02, 0, 0, 0, 0.03, 0,0,0,0,0, 0.02, 0,0,0,0,0,0, 0.02]
curve = state.vars.curve
#vykladani po 5ti kusech, když zbývají 2 a méně, tak děláme nový výklad
vykladka = state.vars.vykladka
#kolik muzu max vylozit
kolikmuzu = int((int(state.vars.maxpozic) - int(state.positions))/int(state.vars.chunk))
if kolikmuzu < vykladka: vykladka = kolikmuzu
if len(curve) < vykladka:
vykladka = len(curve)
qty = int(state.vars.chunk)
last_price = price2dec(state.interface.get_last_price(state.symbol))
#profit = float(state.vars.profit)
price = last_price
##prvni se vyklada na aktualni cenu, další jdou podle krivky, nula v krivce zvyšuje množství pro následující iteraci
state.buy_l(price=price, size=qty)
print("prvni limitka na aktuální cenu. Další podle křicvky", price, qty)
for i in range(0,vykladka-1):
price = price2dec(float(price - curve[i]))
if price == last_price:
qty = qty + int(state.vars.chunk)
else:
state.buy_l(price=price, size=qty)
print(i,"BUY limitka - delta",curve[i]," cena:", price, "mnozstvi:", qty)
qty = int(state.vars.chunk)
last_price = price
state.vars.blockbuy = 1
state.vars.jevylozeno = 1
#CBAR protection, only 1x order per CBAR - then wait until another confirmed bar
if state.vars.blockbuy == 1 and state.rectype == RecordType.CBAR:
if state.bars.confirmed[-1] == 0:
print("OCHR: multibuy protection. waiting for next bar")
return 0
# pop potvrzeni jeste jednou vratime (aby se nekoupilo znova, je stale ten stejny bar)
# a pak dalsi vejde az po minticku
else:
# pro vykladaci
state.vars.blockbuy = 0
return 0
try:
print(state.vars.MA, "MACKO")
print(state.bars.hlcc4)
state.indicators.ema = ema(state.bars.hlcc4, state.vars.MA) #state.bars.vwap
#trochu prasarna, EMAcko trunc na 3 mista - kdyz se osvedci, tak udelat efektivne
state.indicators.ema = [trunc(i,3) for i in state.indicators.ema]
ic(state.vars.MA, state.vars.Trend, state.indicators.ema[-5:])
except Exception as e:
print("No data for MA yet", str(e))
print("is falling",isfalling(state.indicators.ema,state.vars.Trend))
print("is rising",isrising(state.indicators.ema,state.vars.Trend))
#and data['index'] > state.vars.lastbuyindex+state.vars.Trend:
#neni vylozeno muzeme nakupovat
if ic(state.vars.jevylozeno) == 0:
print("Neni vylozeno, muzeme testovat nakup")
if isfalling(state.indicators.ema,state.vars.Trend):
print("BUY MARKET")
ic(data['updated'])
ic(state.time)
#zatim vykladame full
#positions = int(int(state.vars.maxpozic)/int(state.vars.chunk))
vyloz()
## testuje aktualni cenu od nejvyssi visici limitky
##toto spoustet jednou za X iterací - ted to jede pokazdé
#pokud to ujede o vic, rusime limitky
#TODO: zvazit jestli nechat i pri otevrenych pozicich, zatim nechavame
#TODO int(int(state.oa.poz)/int(state.variables.chunk)) > X
#TODO predelat mechanismus ticků (zrelativizovat), aby byl pouzitelny na tituly s ruznou cenou
#TODO spoustet 1x za X iteraci nebo cas
if state.vars.jevylozeno == 1:
#pokud mame vylozeno a cena je vetsi nez 0.04
if len(state.vars.pendingbuys)>0:
maxprice = max(state.vars.pendingbuys.values())
print("max cena v orderbuys", maxprice)
if state.interface.get_last_price(state.symbol) > float(maxprice) + state.vars.ticks2reset:
print("ujelo to vice nez o " + str(state.vars.ticks2reset) + ", rusime limit buye")
##TODO toto nejak vymyslet - duplikovat?
res = asyncio.run(state.cancel_pending_buys())
#pokud mame vylozeno a pendingbuys se vyklepou a
# 1 vykladame idned znovu
# vyloz()
# 2 nebo - počkat zase na signál a pokračovat dál
# state.vars.blockbuy = 0
# state.vars.jevylozeno = 0
# 3 nebo - počkat na signál s enablovaným lastbuy indexem (tzn. počká nutně ještě pár barů)
#podle BT vyhodnejsi vylozit ihned
if len(state.vars.pendingbuys) == 0:
state.vars.blockbuy = 0
state.vars.jevylozeno = 0
#TODO toto dodelat
#pokud je vylozeno a mame pozice a neexistuje limitka - pak ji vytvorim
# if int(state.oe.poz)>0 and state.oe.limitka == 0:
# #pro jistotu updatujeme pozice
# state.oe.avgp, state.oe.poz = state.oe.pos()
# if int(state.oe.poz) > 0:
# cena = round(float(state.oe.avgp) + float(state.oe.stratvars["profit"]),2)
# print("BUGF: limitka neni vytvarime, a to za cenu",cena,"mnozstvi",state.oe.poz)
# print("aktuzalni ltp",ltp.price[state.oe.symbol])
# try:
# state.oe.limitka = state.oe.sell_noasync(cena, state.oe.poz)
# print("vytvorena limitka", state.oe.limitka)
# except Exception as e:
# print("Neslo vytvorit profitku. Problem,ale jedeme dal",str(e))
# pass
# ##raise Exception(e)
print(10*"*","NEXT STOP",10*"*")
def init(state: StrategyState):
#place to declare new vars
print("INIT v main",state.name)
state.indicators['ema'] = []
def main():
try:
strat_settings = tomli.loads("]] this is invalid TOML [[")
except tomli.TOMLDecodeError:
print("Yep, definitely not valid.")
#strat_settings = dict_replace_value(strat_settings, "None", None)
name = os.path.basename(__file__)
se = Event()
pe = Event()
s = StrategyOrderLimitVykladaci(name = name, symbol = "BAC", account=Account.ACCOUNT2, next=next, init=init, stratvars=stratvars, open_rush=40, close_rush=0, pe=pe, se=se)
s.set_mode(mode = Mode.PAPER,
debug = False,
start = datetime(2023, 3, 30, 9, 30, 0, 0, tzinfo=zoneNY),
end = datetime(2023, 3, 31, 16, 0, 0, 0, tzinfo=zoneNY),
cash=100000)
#na sekundovem baru nezaokrouhlovat MAcko
s.add_data(symbol="BAC",rectype=RecordType.BAR,timeframe=5,minsize=100,update_ltp=True,align=StartBarAlign.ROUND,mintick=0, exthours=True)
#s.add_data(symbol="C",rectype=RecordType.BAR,timeframe=1,filters=None,update_ltp=True,align=StartBarAlign.ROUND,mintick=0)
s.start()
print("zastavujeme")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,103 @@
from strategy.base import Strategy, StrategyState
from strategy.strategyOrderLimitWatched import StrategyOrderLimitWatched
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode
from indicators import ema
from rich import print
from utils.utils import ltp, isrising, isfalling,trunc,AttributeDict, zoneNY
from datetime import datetime
from icecream import install, ic
install()
ic.configureOutput(includeContext=True)
#ic.disable()
""""
Simple strategie pro test backtesting
"""
def next(data, state: StrategyState):
print(10*"*","NEXT START",10*"*")
ic(state.avgp, state.positions)
ic(state.vars.lastbuyindex)
ic(data)
ic(state.positions)
ic(state.vars.watched)
ic(state.vars.wait)
try:
state.indicators.ema = ema(state.bars.hlcc4, state.vars.MA) #state.bars.vwap
#trochu prasarna, EMAcko trunc na 3 mista - kdyz se osvedci, tak udelat efektivne
state.indicators.ema = [trunc(i,3) for i in state.indicators.ema]
ic(state.vars.MA, state.vars.Trend, state.indicators.ema[-5:])
except Exception as e:
print("No data for MA yet", str(e))
print("is falling",isfalling(state.indicators.ema,state.vars.Trend))
print("is rising",isrising(state.indicators.ema,state.vars.Trend))
#ZDE JSEM SKONCIL
#nejprve zacit s BARy
#TODO vyzkoušet limit buy - vetsina z nakupu by se dala koupit o cent dva mene
#proto dodělat LTP pro BT, neco jako get_last_price(self.state.time)
##TODO vyzkouset hlidat si sell objednavku sam na zaklade tradu
# v pripade ze to jde nahoru(is rising - nebo jiny indikator) tak neprodavat
#vyuzit CBARy k tomuto .....
#triggerovat buy treba po polovine CBARu, kdyz se cena bude rovnat nebo bude nizsi nez low
#a hned na to (po potvrzeni) hlidat sell +0.01 nebo kdyz roste nechat rust.vyzkouset na LIVE
datetime.fromtimestamp(state.last_trade_time)
casbaru = datetime.fromtimestamp(state.last_trade_time)-data['time']
kupuj = casbaru.seconds > int(int(data['resolution']) * 0.4)
ic(kupuj)
ic(casbaru.seconds)
#kupujeme kdyz v druhe polovine baru je aktualni cena=low (nejnizsi)
#isrising(state.indicators.ema,state.vars.Trend)
#kdyz se v jednom baru pohneme o 2
if kupuj and data['confirmed'] != 1 and data['close'] == data['low'] and float(data['close']) + 0.01 < data['open'] and state.vars.wait is False and state.vars.watched is None:
print("BUY MARKET")
ic(data['updated'])
ic(state.time)
##updatneme realnou cenou po fillu
state.buy()
state.vars.wait = True
if state.vars.watched and state.vars.wait is False:
currprice = state.interface.get_last_price(symbol = state.symbol)
ic(currprice)
if float(currprice) > (float(state.vars.watched) + float(state.vars.profit)):
ic(state.time)
ic("prodavame", currprice)
print("PRODAVAME")
##vymyslet jak odchytavat obecne chyby a vracet cislo objednavky
state.interface.sell(size=1)
state.vars.wait = True
print(10*"*","NEXT STOP",10*"*")
def init(state: StrategyState):
#place to declare new vars
print("INIT v main",state.name)
state.vars['novaprom'] = 4
state.indicators['ema'] = []
def main():
stratvars = AttributeDict(maxpozic = 1, chunk = 1, MA = 2, Trend = 2, profit = 0.005, lastbuyindex=-6, pendingbuys={},watched = None, wait = False)
s = StrategyOrderLimitWatched(name = "BackTEST", symbol = "BAC", next=next, init=init, stratvars=stratvars, debug=False)
s.set_mode(mode = Mode.PAPER,
start = datetime(2023, 3, 24, 11, 30, 0, 0, tzinfo=zoneNY),
end = datetime(2023, 3, 24, 11, 45, 0, 0, tzinfo=zoneNY),
cash=100000)
#na sekundovem baru nezaokrouhlovat MAcko
s.add_data(symbol="BAC",rectype=RecordType.CBAR,timeframe=5,filters=None,update_ltp=True,align=StartBarAlign.ROUND,mintick=0)
#s.add_data(symbol="C",rectype=RecordType.BAR,timeframe=1,filters=None,update_ltp=True,align=StartBarAlign.ROUND,mintick=0)
s.start()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,70 @@
from strategy.base import Strategy
from strategy.base import StrategyState
from enums import RecordType, StartBarAlign, Mode
from config import API_KEY, SECRET_KEY, MAX_BATCH_SIZE, PAPER
from indicators import ema
from rich import print
from utils import ltp, isrising, isfalling,trunc,AttributeDict
from datetime import datetime
""""
Simple strategie pro měření roundtripu na konkrétním prostředí
- koupí 1 akcii a vypíše časy
- tradu který triggeroval
- čas triggeru buy
- příchod zpětné notifikace NEW
- příchod zpětné notifikace FILL
- vypíše trade, když přijde do agregátoru (vyžaduje do agregátoru na řádek 79: if int(data['s']) == 1: print(data))
- vyžaduje ve strategy base v orderupdate
- print("NOTIFICATION ARRIVED AT:", datetime.now().timestamp(), datetime.now())
- print(data)
výsledek latencyroudntrip.log
"""
def next(data, state: StrategyState):
print("avgp:", state.avgp)
print("positions", state.positions)
print("přišly tyto data", data)
print("bar updated time:", data['updated'], datetime.fromtimestamp(data['updated']))
print("state time(now):", state.time, datetime.fromtimestamp(state.time))
#print("trades history", state.trades)
#print("bar history", state.bars)
print("ltp", ltp.price["BAC"], ltp.time["BAC"])
try:
ema_output = ema(state.bars.hlcc4, state.vars.MA) #state.bars.vwap
ema_output = [trunc(i,3) for i in ema_output]
print("emacko na wvap",state.vars.MA,":", ema_output[-5:])
except:
print("No data for MA yet")
print("MA is falling",state.vars.Trend,"value:",isfalling(ema_output,state.vars.Trend))
print("MA is rising",state.vars.Trend,"value:",isrising(ema_output,state.vars.Trend))
if isfalling(ema_output,state.vars.Trend) and state.vars.blockbuy == 0:
print("kupujeme MARKET")
print("v baru mame cas posledniho tradu", data['updated'])
print("na LIVE je skutecny cas - tento ", state.time)
print("v nem odesilame")
state.interface.buy(time=state.time)
state.vars.blockbuy = 1
def init(state: StrategyState):
print("INIT strategie", state.name, "symbol", state.symbol)
def main():
stratvars = AttributeDict(maxpozic = 200, chunk = 10, MA = 3, Trend = 3, profit = 0.01, blockbuy=0, lastbuyindex=0, pendingbuys={})
s = Strategy(name = "BackTEST", symbol = "BAC", next=next, init=init, stratvars=stratvars)
#s.set_mode(mode = Mode.BT, start= datetime(2023, 3, 16, 15, 54, 30, 0), end=datetime(2023, 3, 16, 15, 54, 40, 999999))
s.add_data(symbol="BAC",rectype=RecordType.BAR,timeframe=5,filters=None,update_ltp=True,align=StartBarAlign.ROUND,mintick=0)
#s.add_data(symbol="C",rectype=RecordType.BAR,timeframe=1,filters=None,update_ltp=True,align=StartBarAlign.ROUND,mintick=0)
s.start()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,5 @@
##pro refactor vykladaci strategie: tipy:
##pri CANCEL pendindbuys - lokalni pending buys zrušit hnedka po synchronním odeslání, nemusim cekat na potvrzeni
##ve zpetne notifikaci FILLU - je uvedena aktuální počet pozice - tzn. nemusím volat POS, ale jen si je dotahnu odsud. Pozor avgp tu neni.

View File

@ -0,0 +1,200 @@
from strategy import MyStrategy, StrategyState, Strategy
from enums import RecordType, StartBarAlign
from config import API_KEY, SECRET_KEY, MAX_BATCH_SIZE, PAPER
from indicators import ema
from rich import print
from utils import ltp, isrising, isfalling,trunc
""""
TBD - zpomalit - nekupovat okamzite nechat dychat
MA Vykládcí Strategie s LIMIT BUY
# aktualni nastaveni - VELMI AGRESIVNI, STALE KUPUJE, IDEALNI NA POTVRZENE RUSTOVE DNY
- jede na 10s
- BUY and HOLD alternative
- dat do seznamu hotovych strategii
atributy:
ticks2reset - počet ticků po kterých se resetnou prikazy pokud neni plneni
TODO:
- pridat reconciliaci po kazdem X tem potvrzenem baru - konzolidace otevrenych pozic a limitek
- do kazde asynchronni notifkace orderupdate dat ochranu, kdyz uz ten stav neplati (tzn. napr. pro potvrzeni buye se uz prodalo)
- podchytit: kdykoliv limitka neexistuje, ale mam pozice, tak ji vytvorit (podchytit situace v rush hours)
- cancel pendign buys - dictionary changed size during iteration podychytit. lock
"""
ticks2reset = 0.03
#TODO pokud bar klesne o jeden nebo vice - tak signál - DEFENZIVNI MOD
#TODO pouzivat tu objekt ochrana (ktery jen vlozim do kodu a kdyz vrati exceptionu tak jdeme do dalsi iterace)
# tak zustane strategie cista
#TODO rušit (pending buys) když oe.poz = 0 a od nejvetsi pending buys je
# ltp.price vice nez 5 ticků
def next(data, state: StrategyState):
def vyloz(pozic: int):
print("vykladame na pocet pozic", pozic)
# defenzivni krivka
curve = [0.01, 0.01, 0.01, 0.02, 0.02, 0.02, 0.02,0.03,0.03,0.03,0.03, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04]
#cent curve = [0.01, 0.01, 0.01,0.01, 0.01, 0.01,0.01, 0.01,0.01, 0.01, 0.01, 0.01,0.01, 0.01,0.01, 0.01,0.01, 0.01,0.01, 0.01,0.01, 0.01,0.01, 0.01,0.01, 0.01]
#defenzivnejsi s vetsimi mezerami v druhe tretine a vetsi vahou pro dokupy
# krivka pro AVG, tzn. exponencialne pridavame 0.00
curve = [0.01, 0, 0.01, 0, 0, 0.01, 0, 0, 0, 0.01, 0, 0, 0, 0, 0.01, 0, 0, 0, 0, 0, 0.01, 0,0,0,0,0,0, 0.01, 0,0,0,0,0,0,0,0,0.01,0,0,0,0,0,0,0,0,0, 0.01,0,0,0,0,0,0,0,0,0,0.01, 0,0,0,0,0,00,0,0,0, 0.5, 0,0,0,0,0.5,0,0,0]
# 10ty clen je o 0.05 tzn.triggeruje nam to tick2reset
#curve = [0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.02, 0.02, 0.05, 0.01, 0.04, 0.01, 0.01, 0.04, 0.05, 0.03, 0.05, 0.01, 0.03, 0.01,0.01, 0.04, 0.01, 0.05,0.01, 0.01,0.01, 0.01]
#defenzivni krivku nastavime vetsimi mezerami a v nich 0.01 - tim se prida vetsi mnostvi a vic se naredi
# 0.04, 0.01,
#curve = [0.01,0.01, 0.01, 0.02, 0.02, 0.02, 0.02]
#cena pro prvni objednavky
price = trunc(float(ltp.price[state.oe.symbol]),2)
print("aktualni cena pri vykladu - pro prvni", price)
qty = int(state.variables.chunk)
last_price = price
if len(curve) < pozic:
pozic = len(curve)
#stejné ceny posilame jako jednu objednávku
for i in range(0,pozic):
price = round(float(price - curve[i]),2)
if price == last_price:
qty = qty + int(state.variables.chunk)
else:
#flush last_price and stored qty
# OPT: pokud bude kupovat prilis brzy, osvedcila se prvni cena -0.01 (tzn. stavi prehodit last_price za price)
state.oe.buy_l(price=last_price, size=qty, force=1)
print(i,"BUY limitka - delta",curve[i]," cena:", price, "mnozstvi:", qty)
qty = int(state.variables.chunk)
last_price = price
#TODO pokud cena stejna jako predchozi, tak navys predchozi - abychom nemeli vice objednavek na stejne cene (zbytecne)
print("pending buys", state.oe.stratvars['pendingbuys'])
print("je vylozeno",state.oe.stratvars['jevylozeno'])
print("avg,poz,limitka",state.oe.avgp, state.oe.poz, state.oe.limitka)
print("last buy price", state.oe.lastbuy)
#CBAR protection, only 1x order per CBAR - then wait until another confirmed bar
if state.variables.blockbuy == 1:
if state.bars.confirmed[-1] == 0:
print("OCHR: multibuy protection. waiting for next bar")
return 0
# pop potvrzeni jeste jednou vratime (aby se nekoupilo znova, je stale ten stejny bar)
# a pak dalsi vejde az po minticku
else:
# pro vykladaci
state.variables.blockbuy = 0
return 0
#print(state.bars) .
# print("next")
# print(data)
#TODO zkusit hlcc4
try:
ema_output = ema(state.bars.vwap, state.variables.MA)
#trochu prasarna, EMAcko trunc na 3 mista - kdyz se osvedci, tak udelat efektivne
ema_output = [trunc(i,3) for i in ema_output]
print("emacko na wvap",state.variables.MA,":", ema_output[-5:])
except:
print("No data for MA yet")
print("MA is falling",state.variables.Trend,"value:",isfalling(ema_output,state.variables.Trend))
print("MA is rising",state.variables.Trend,"value:",isrising(ema_output,state.variables.Trend))
## testuje aktualni cenu od nejvyssi visici limitky
##toto spoustet jednou za X iterací - ted to jede pokazdé
#pokud to ujede o vic, rusime limitky
#TODO: zvazit jestli nechat i pri otevrenych pozicich, zatim nechavame
#TODO int(int(state.oa.poz)/int(state.variables.chunk)) > X
if state.oe.stratvars['jevylozeno'] == 1: # and int(state.oe.poz) == 0:
#pokud mame vylozeno a cena je vetsi nez 0.04
if len(state.oe.stratvars['pendingbuys'])>0:
a = max(state.oe.stratvars['pendingbuys'].values())
print("max cena v orderbuys", a)
if float(ltp.price[state.oe.symbol]) > float(a) + ticks2reset:
print("ujelo to vice nez o 4, rusime limit buye")
state.oe.cancel_pending_buys()
state.oe.stratvars['jevylozeno'] = 0
#pokud je vylozeno a mame pozice a neexistuje limitka - pak ji vytvorim
if int(state.oe.poz)>0 and state.oe.limitka == 0:
#pro jistotu updatujeme pozice
state.oe.avgp, state.oe.poz = state.oe.pos()
if int(state.oe.poz) > 0:
cena = round(float(state.oe.avgp) + float(state.oe.stratvars["profit"]),2)
print("BUGF: limitka neni vytvarime, a to za cenu",cena,"mnozstvi",state.oe.poz)
print("aktuzalni ltp",ltp.price[state.oe.symbol])
try:
state.oe.limitka = state.oe.sell_noasync(cena, state.oe.poz)
print("vytvorena limitka", state.oe.limitka)
except Exception as e:
print("Neslo vytvorit profitku. Problem,ale jedeme dal",str(e))
pass
##raise Exception(e)
if state.oe.stratvars['jevylozeno'] == 0:
print("neni vylozeno. Muzeme nakupovat")
# testuji variantu, ze kupuji okamzite, nehlede na vyvoj
if isfalling(ema_output,state.variables.Trend): # or 1==1:
## vyloz pro pocet pozic (maximalni minus aktualni)
#kolik nam zbyva pozic
#HOKUS: vykladame pouze polovinu pozic - dalsi polovinu davame v dalsimrunu
# a = available pozice a/2
a = int(int(state.variables.maxpozic)/int(state.variables.chunk)-(int(state.oe.poz)/int(state.variables.chunk)))
a = int(a)
print("Vykladame na pocet pozic", a)
vyloz(pozic=a)
#blokneme nakupy na dalsi bar
state.variables.blockbuy = 1
state.oe.stratvars['jevylozeno'] = 1
#ulozime id baru
# state.variables.lastbuyindex = state.bars.index[-1]
# je vylozeno
else:
## po kazde 4te pozici delame revykladani na aktualni zbytek pozic
if (int(state.oe.poz)/(int(state.variables.chunk)) % 4 == 0):
print("ctvrta pozice - v budoucnu realignujeme")
# state.oe.cancel_pending_buys()
# ##smazeme ihned pole - necekame na notifiaci
# vyloz((int(state.variables.maxpozic)-int(state.oe.poz)/state.variables.chunk))
#kazdy potvrzeny bar dotahneme pro jistotu otevřené objednávky a nahradíme si stav aktuálním
#pro jistotu update pozic - kdyz se nic nedeje nedeje
#pripadne dat pryc
#print("upatujeme pozice")
#state.oe.avgp, state.oe.poz = state.oe.pos()
def init(state: StrategyState):
print("init - zatim bez data")
print(state.oe.symbol)
print(state.oe.pos())
print()
def main():
stratvars = dict(maxpozic = 2000, chunk = 20, MA = 3, Trend = 4, profit = 0.01, blockbuy=0, lastbuyindex=0, pendingbuys={}, jevylozeno=0)
s = MyStrategy("BAC",paper=PAPER, next=next, init=init, stratvars=stratvars)
s.add_data(symbol="BAC",rectype=RecordType.CBAR,timeframe=12,filters=None,update_ltp=True,align=StartBarAlign.ROUND,mintick=4)
s.start()
if __name__ == "__main__":
main()

0
v2realbot/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

View File

View File

@ -0,0 +1,816 @@
#import os,sys
#sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
"""
Backtester component, allows to:
pro lepší trasovatelnost máme následující razítka
open orders
- submitted_at
trades
- submitted_at
- filled_at
execute_orders_and_callbacks(time)
- called before iteration
- execute open orders before "time" and calls notification callbacks
market buy
limit buy
market sell
limit sell
cancel order by id
replace order by id
get positions
STATUSES supported:
- FILLED (including callbacks)
not supported: NEW, ACCEPTED, CANCELED (currently no callback action will be backtestable on those)
- případné nad těmito lze dát do synchronní části (api vrací rovnou zda objednávka neexistuje, pokud existuje tak předpokládáme vyplnění)
supports standard validations and blocking of share and cash upon order submit
supports only GTC order validity
no partial fills
RETURN
1 - ok
0 - ok, noaction
- 1 - error
"""
from uuid import UUID, uuid4
from alpaca.trading.enums import OrderSide, OrderStatus, TradeEvent, OrderType
from v2realbot.common.model import TradeUpdate, Order
#from rich import print
import threading
import asyncio
from v2realbot.config import BT_DELAYS
from v2realbot.utils.utils import AttributeDict, ltp, zoneNY, trunc, count_decimals,print
from v2realbot.utils.tlog import tlog
from datetime import datetime, timedelta
import pandas as pd
#import matplotlib.pyplot as plt
#import seaborn; seaborn.set()
#import mplfinance as mpf
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import numpy as np
from bisect import bisect_left
from v2realbot.utils.dash_save_html import make_static
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output
from dash import dcc, html, dash_table, Dash
from config import DATA_DIR
""""
LATENCY DELAYS
.000 trigger - last_trade_time (.4246266)
+.020 vstup do strategie a BUY (.444606)
+.023 submitted (.469198)
+.008 filled (.476695552)
+.023 fill not(.499888)
"""
lock = threading.Lock
#todo nejspis dat do classes, aby se mohlo backtestovat paralelne
#ted je globalni promena last_time_now a self.account a cash
class Backtester:
def __init__(self, symbol: str, order_fill_callback: callable, btdata: list, bp_from: datetime, bp_to: datetime, cash: float = 100000):
#this TIME value determines true time for submit, replace, cancel order should happen (allowing past)
#it is set by every iteration of BT or before fill callback - allowing past events to happen
self.time = None
self.symbol = symbol
self.order_fill_callback = order_fill_callback
self.btdata = btdata
self.backtest_start = None
self.backtest_end = None
self.cash_init = cash
#backtesting period
self.bp_from = bp_from
self.bp_to = bp_to
self.cash = cash
self.trades = []
self.account = { "BAC": [0, 0] }
# { "BAC": [avgp, size] }
self.open_orders =[]
# self.open_orders = [Order(id=uuid4(),
# submitted_at = datetime(2023, 3, 17, 9, 30, 0, 0, tzinfo=zoneNY),
# symbol = "BAC",
# qty = 1,
# status = OrderStatus.ACCEPTED,
# order_type = OrderType.LIMIT,
# side = OrderSide.BUY,
# limit_price=22.4),
# Order(id=uuid4(),
# submitted_at = datetime(2023, 3, 17, 9, 30, 00, 0, tzinfo=zoneNY),
# symbol = "BAC",
# qty = 1,
# order_type = OrderType.MARKET,
# status = OrderStatus.ACCEPTED,
# side = OrderSide.BUY)]
#
def execute_orders_and_callbacks(self, intime: float):
"""""
Voláno ze strategie před každou iterací s časem T.
Provede exekuci otevřených objednávek, které by se v reálu vyplnili do tohoto času.
Pro vyplněné posílá fill notifikaci a volá callback s časem FILLu.
- current time - state.time
- actual prices - self.btdata
- callback after order fill - self.order_fill_callback
- set time for order fill callback - self.time
"""""
print(10*"*",intime,"Exec OPEN ORDERS ",len(self.open_orders)," time", datetime.fromtimestamp(intime).astimezone(zoneNY),10*"*")
# print("cash before", cash)
# print("BT: executing pending orders")
# print("list before execution", self.open_orders)
if len(self.open_orders) == 0:
ic("no pend orders")
return 0
changes = 0
#iterating while removing items - have to use todel list
todel = []
#with lock:
"""
Pripravime si pracovni list
btdata obsahuje vsechny aktualni timestampy tradu a jejich cenu.
1) pracujeme vzdy OD zacatku listu DO indexu odpovidajici aktualnimu casu
2) zjistime si index a pak iterujeme nad nim
3) po skonceni pak tento pracovni kus umazeme
"""
"""
Assumes myList is sorted. Returns first biggeer value to the number.
"""
index_end = bisect_left(self.btdata, (intime,))
# #find index of state.time in btdata - nahrazeno BISECT
# for index_end in range(len(self.btdata)):
# #print(btdata[i][0])
# #print(i)
# if self.btdata[index_end][0] >= intime:
# break
#pracovni list
ic("work_range 0:index_end")
ic(index_end)
work_range = self.btdata[0:index_end]
ic(len(work_range))
#print("index_end", i)
#print("oriznuto",self.btdata[0:i+1])
for order in self.open_orders:
#pokud je vyplneny symbol, tak jedeme jen tyto, jinak vsechny
print(order.id, datetime.timestamp(order.submitted_at), order.symbol, order.side, order.order_type, order.qty, order.limit_price, order.submitted_at)
if order.canceled_at:
ic("deleting canceled order",order.id)
todel.append(order)
elif not self.symbol or order.symbol == self.symbol:
#pricteme mininimalni latency od submittu k fillu
if order.submitted_at.timestamp() + BT_DELAYS.sub_to_fill > float(intime):
ic("too soon for",order.id)
#try to execute
else:
#try to execute specific order
a = self._execute_order(o = order, intime=intime, work_range=work_range)
if a == 1:
ic("EXECUTED")
todel.append(order)
changes = 1
else:
ic("NOT EXECUTED",a)
#ic("istodel",todel)
#vymazu z pending orderu vschny zprocesovane nebo ty na výmaz
for i in todel:
self.open_orders.remove(i)
todel = {}
#tady udelat pripadny ořez self.btdata - priste zaciname od zacatku
#ic("before delete", len(self.btdata))
#TEST zkusime to nemazat, jak ovlivni performance
#Mazeme, jinak je to hruza
del self.btdata[0:index_end-2]
#ic("after delete",len(self.btdata[0:index_end]))
if changes: return 1
else: return 0
# print("pending orders after execution", self.open_orders)
# print("trades after execution", trades)
# print("self.account after execution", self.account)
# print("cash after", cash)
def _execute_order(self, o: Order, intime: float, work_range):
"""tries to execute order
o - specific Order
time - intime
work_range - aktualni slice of btdata pro tuto iteraci [(timestamp,price)] """
fill_time = None
fill_price = None
order_min_fill_time = o.submitted_at.timestamp() + BT_DELAYS.sub_to_fill
ic(order_min_fill_time)
ic(len(work_range))
if o.order_type == OrderType.LIMIT:
if o.side == OrderSide.BUY:
for i in work_range:
#print(i)
##najde prvni nejvetsi čas vetsi nez minfill a majici odpovídající cenu
## pro LIMITku nejspíš přidat BT_DELAY.LIMIT_OFFSET, aby se nevyplnilo hned jako prvni s touto cenou
## offest by se pocital od nize nalezeneho casu, zvetsil by ho o LIMIT_OFFSET a zjistil, zda by
##v novem case doslo take k plneni a tam ho vyplnil. Uvidime az jestli bude aktualni prilis optimisticke.
## TBD zjistit na LIVE jaky je tento offset
if float(i[0]) > float(order_min_fill_time+BT_DELAYS.limit_order_offset) and i[1] <= o.limit_price:
#(1679081919.381649, 27.88)
ic(i)
fill_time = i[0]
fill_price = i[1]
print("FILL LIMIT BUY at", fill_time, datetime.fromtimestamp(fill_time).astimezone(zoneNY), "at",i[1])
break
else:
for i in work_range:
#print(i)
if float(i[0]) > float(order_min_fill_time+BT_DELAYS.limit_order_offset) and i[1] >= o.limit_price:
#(1679081919.381649, 27.88)
ic(i)
fill_time = i[0]
fill_price = i[1]
print("FILL LIMIT SELL at", fill_time, datetime.fromtimestamp(fill_time).astimezone(zoneNY), "at",i[1])
break
elif o.order_type == OrderType.MARKET:
for i in work_range:
#print(i)
#najde prvni nejvetsi čas vetsi nez minfill
if i[0] > float(order_min_fill_time):
#(1679081919.381649, 27.88)
ic(i)
fill_time = i[0]
fill_price = i[1]
print("FILL ",o.side,"MARKET at", fill_time, datetime.fromtimestamp(fill_time).astimezone(zoneNY), "cena", i[1])
break
else:
print("unknown order type")
return -1
if not fill_time:
ic("not FILLED")
return 0
else:
#order FILLED - update trades and account and cash
o.filled_at = datetime.fromtimestamp(float(fill_time))
o.filled_qty = o.qty
o.filled_avg_price = float(fill_price)
o.status = OrderStatus.FILLED
ic(o.filled_at, o.filled_avg_price)
a = self.update_account(o = o)
if a < 0:
tlog("update_account ERROR")
return -1
trade = TradeUpdate(order = o,
event = TradeEvent.FILL,
execution_id = str(uuid4()),
timestamp = datetime.fromtimestamp(fill_time),
position_qty= self.account[o.symbol][0],
price=float(fill_price),
qty = o.qty,
value = float(o.qty*fill_price),
cash = self.cash,
pos_avg_price = self.account[o.symbol][1])
self.trades.append(trade)
# do notification with callbacks
#print("pred appendem",self.open_orders)
self._do_notification_with_callbacks(tradeupdate=trade, time=float(fill_time))
#print("po appendu",self.open_orders)
#ohandlovat nejak chyby? v LIVE je to asynchronni a takze neni ohandlovano, takze jen print
return 1
def _do_notification_with_callbacks(self, tradeupdate: TradeUpdate, time: float):
#do callbacku je třeba zpropagovat filltime čas (včetně latency pro notifikaci), aby se pripadne akce v callbacku udály s tímto časem
self.time = time + float(BT_DELAYS.fill_to_not)
print("current bt.time",self.time)
#print("FILL NOTIFICATION: ", tradeupdate)
res = asyncio.run(self.order_fill_callback(tradeupdate))
return 0
def update_account(self, o: Order):
#updatujeme self.account
#pokud neexistuje klic v accountu vytvorime si ho
if o.symbol not in self.account:
# { "BAC": [size, avgp] }
self.account[o.symbol] = [0,0]
if o.side == OrderSide.BUY:
#[size, avgp]
if (self.account[o.symbol][0] + o.qty) == 0: newavgp = 0
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.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
if newsize == 0: newavgp = 0
else:
if self.account[o.symbol][1] == 0:
newavgp = o.filled_avg_price
else:
newavgp = self.account[o.symbol][1]
self.account[o.symbol] = [newsize, newavgp]
self.cash = float(self.cash + (o.qty * o.filled_avg_price))
return 1
else:
print("neznaama side", o.side)
return -1
"""""
BACKEND PRO API
TODO - možná toto předělat a brát si čas z bt.time - upravit také v BacktestInterface
BUG:
"""""
def get_last_price(self, time: float, symbol: str = None):
"""""
returns equity price in timestamp. Assumes myList is sorted. Returns first lower value to the number.
optimalized as bisect left
"""""
pos = bisect_left(self.btdata, (time,))
ic("vracime last price")
ic(time)
if pos == 0:
ic(self.btdata[0][1])
return self.btdata[0][1]
afterTime, afterPrice = self.btdata[pos-1]
ic(afterPrice)
return afterPrice
#not optimalized:
# for i in range(len(self.btdata)):
# #print(btdata[i][0])
# #print(i)
# if self.btdata[i][0] >= time:
# break
# ic(time, self.btdata[i-1][1])
# ic("get last price")
# return self.btdata[i-1][1]
def submit_order(self, time: float, symbol: str, side: OrderSide, size: int, order_type: OrderType, price: float = None):
"""submit order
- zakladni validace
- vloží do self.open_orders s daným časem
- vrátí orderID
status NEW se nenotifikuje
TBD dotahovani aktualni ceny podle backtesteru
"""
print("BT: submit order entry")
if not time or time < 0:
print("time musi byt vyplneny")
return -1
if not size or int(size) < 0:
print("size musi byt vetsi nez 0")
return -1
if (order_type != OrderType.MARKET) and (order_type != OrderType.LIMIT):
tlog("ordertype market and limit supported only", order_type)
return -1
if not side == OrderSide.BUY and not side == OrderSide.SELL:
print("side buy/sell required")
return -1
if order_type == OrderType.LIMIT and count_decimals(price) > 2:
print("only 2 decimals supported", price)
return -1
#pokud neexistuje klic v accountu vytvorime si ho
if symbol not in self.account:
# { "BAC": [size, avgp] }
self.account[symbol] = [0,0]
#check for available quantity
if side == OrderSide.SELL:
reserved = 0
#with lock:
for o in self.open_orders:
if o.qty == OrderSide.SELL and o.symbol == symbol:
reserved += o.qty
#print("blokovano v open orders pro sell: ", reserved)
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)
return -1
#check for available cash
if side == OrderSide.BUY:
reserved = 0
#with lock:
for o in self.open_orders:
if o.qty == OrderSide.BUY:
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)
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)))
return -1
id = str(uuid4())
order = Order(id=id,
submitted_at = datetime.fromtimestamp(float(time)),
symbol=symbol,
order_type = order_type,
status = OrderStatus.ACCEPTED,
side=side,
qty=int(size),
limit_price=(float(price) if price else None))
self.open_orders.append(order)
ic("order SUBMITTED", order)
return id
def replace_order(self, id: str, time: float, size: int = None, price: float = None):
"""replace order
- zakladni validace vrací synchronně
- vrací číslo nové objednávky
"""
print("BT: replace order entry",id,size,price)
if not price and not size:
print("size or price required")
return -1
if len(self.open_orders) == 0:
print("BT: order doesnt exist")
return 0
#with lock:
for o in self.open_orders:
print(o.id)
if str(o.id) == str(id):
newid = str(uuid4())
o.id = newid
o.submitted_at = datetime.fromtimestamp(time)
o.qty = int((size if size else o.qty))
o.limit_price = float(price if price else o.limit_price)
print("order replaced")
return newid
print("BT: replacement order doesnt exist")
return 0
def cancel_order(self, time: float, id: str):
"""cancel order
- základní validace vrací synchronně
- vymaže objednávku z open orders
- nastavuje v open orders flag zrušeno, který pak exekuce ignoruje a odstraní
(je tak podchycen stav, kdy se cancel volá z bt callbacku a z iterovaného listu by se odstraňovalo během iterace)
TODO: teoreticky bych pred cancel order mohl zavolat execution, abych vyloucil, ze za 20ms zpozdeni, kdy se vola alpaca mi neprojde nejaka objednavka
spise do budoucna
"""
print("BT: cancel order entry",id)
if len(self.open_orders) == 0:
print("BTC: order doesnt exist")
return 0
#with lock:
for o in self.open_orders:
if str(o.id) == id:
o.canceled_at = time
print("set as canceled in self.open_orders")
return 1
print("BTC: cantchange. open order doesnt exist")
return 0
def get_open_position(self, symbol: str):
"""get positions ->(avg,size)"""
#print("BT:get open positions entry")
try:
return self.account[symbol][1], self.account[symbol][0]
except:
return (0,0)
def get_open_orders(self, side: OrderSide, symbol: str):
"""get open orders ->list(OrderNotification)"""
print("BT:get open orders entry")
if len(self.open_orders) == 0:
print("BTC: order doesnt exist")
return 0
res = []
#with lock:
for o in self.open_orders:
if str(o.side) == side and o.symbol == symbol:
res.append(o)
return res
def display_backtest_result(self, state):
"""
Displays backtest results chart, trades and orders with option to save the result as static HTML.
"""
#open_orders to dataset
oo_dict = AttributeDict(orderid=[],submitted_at=[],symbol=[],side=[],order_type=[],qty=[],limit_price=[],status=[])
for t in self.open_orders:
oo_dict.orderid.append(str(t.id))
oo_dict.submitted_at.append(t.submitted_at)
oo_dict.symbol.append(t.symbol)
oo_dict.side.append(t.side)
oo_dict.qty.append(t.qty)
oo_dict.order_type.append(t.order_type)
oo_dict.limit_price.append(t.limit_price)
oo_dict.status.append(t.status)
open_orders_df = pd.DataFrame(oo_dict)
open_orders_df = open_orders_df.set_index('submitted_at', drop=False)
#trades to dataset
trade_dict = AttributeDict(orderid=[],timestamp=[],symbol=[],side=[],order_type=[],qty=[],price=[],position_qty=[],value=[],cash=[],pos_avg_price=[])
for t in self.trades:
trade_dict.orderid.append(str(t.order.id))
trade_dict.timestamp.append(t.timestamp)
trade_dict.symbol.append(t.order.symbol)
trade_dict.side.append(t.order.side)
trade_dict.qty.append(t.qty)
trade_dict.price.append(t.price)
trade_dict.position_qty.append(t.position_qty)
trade_dict.value.append(t.value)
trade_dict.cash.append(t.cash)
trade_dict.order_type.append(t.order.order_type)
trade_dict.pos_avg_price.append(t.pos_avg_price)
trade_df = pd.DataFrame(trade_dict)
trade_df = trade_df.set_index('timestamp',drop=False)
#ohlcv dataset (TODO podporit i trady)
hist_df = pd.DataFrame(state.bars)
hist_df = hist_df.set_index('time', drop=False)
#indicators
ind_df = pd.DataFrame(state.indicators)
ind_df = ind_df.set_index('time', drop=False)
#print("Indicators", ind_df)
#print(state.indicators)
#KONEC přípravy dat
fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.02, row_heights=[0.7, 0.3], specs=[[{"secondary_y": True}],[{"secondary_y": True}]])
# fig.add_trace(go.Scatter(x=trade_df.index,
# y=trade_df.cash,
# mode="lines+text",
# name="Value"),
# row = 1, col=1, secondary_y=True)
#add_openorders
fig.add_trace(go.Scatter(x=open_orders_df.index,
y=open_orders_df.limit_price,
mode="markers+text",
name="Open orders",
customdata=open_orders_df.orderid,
marker=dict(size=17, color='blue', symbol='arrow-bar-down'),
text=open_orders_df.qty),
row = 1, col=1, secondary_y=False)
#add trades
fig.add_trace(go.Scatter(x=trade_df.loc[trade_df.side==OrderSide.BUY].index,
y=trade_df.loc[trade_df.side==OrderSide.BUY].price,
mode="markers+text",
name="BUY Trades",
customdata=trade_df.loc[trade_df.side==OrderSide.BUY].orderid,
marker=dict(size=15, color='green', symbol='arrow-up'),
text=trade_df.loc[trade_df.side==OrderSide.BUY].position_qty),
row = 1, col=1, secondary_y=False)
fig.add_trace(go.Scatter(x=trade_df.loc[trade_df.side==OrderSide.SELL].index,
y=trade_df.loc[trade_df.side==OrderSide.SELL].price,
mode="markers+text",
name="SELL Trades",
customdata=trade_df.loc[trade_df.side==OrderSide.SELL].orderid,
marker=dict(size=15, color='red', symbol='arrow-down'),
text=trade_df.loc[trade_df.side==OrderSide.SELL].qty),
row = 1, col=1, secondary_y=False)
#add avgprices of all buy trades
fig.add_trace(go.Scatter(x=trade_df.loc[trade_df.side==OrderSide.BUY].index,
y=trade_df.loc[trade_df.side==OrderSide.BUY].pos_avg_price,
mode="markers+text",
name="BUY Trades avg prices",
customdata=trade_df.loc[trade_df.side==OrderSide.BUY].orderid,
marker=dict(size=15, color='blue', symbol='diamond-wide'),
text=trade_df.loc[trade_df.side==OrderSide.BUY].position_qty),
row = 1, col=1, secondary_y=False)
#display ohlcv
fig.add_trace(go.Candlestick(x=hist_df.index,
open=hist_df['open'],
high=hist_df['high'],
low=hist_df['low'],
close=hist_df['close'],
name = "OHLC"),
row = 1, col=1, secondary_y=False)
#addvwap
fig.add_trace(go.Scatter(x=hist_df.index,
y=hist_df.vwap,
mode="lines",
opacity=1,
name="VWAP"
),
row = 1, col=1,secondary_y=False)
#display indicators from history
for col in ind_df.columns:
fig.add_trace(go.Scatter(x=ind_df.index, y = ind_df[col], mode = 'lines', name = col),
row = 1, col=1, secondary_y=False)
fig.add_trace(go.Bar(x=hist_df.index, y=hist_df.volume, showlegend=True, marker_color='#ef5350', name='Volume'), row=2,
col=1)
fig.update_layout(xaxis_rangeslider_visible=False)
#fig.update_layout(title=f'Backtesting Results '+str(Neco.vars), yaxis_title=f'Price')
fig.update_layout(yaxis_title=f'Price')
fig.update_yaxes(title_text=f'Price', secondary_y=False)
fig.update_yaxes(title_text=f'Cash value', secondary_y=True)
fig.update_yaxes(title_text=f'Volume', row=2, col=1)
fig.update_xaxes(title_text='Date', row=2)
# #remove gaps
# alldays =set(hist_df.time[0]+timedelta(x) for x in range((hist_df.time[len(hist_df.time)-1]- hist_df.time[0]).days))
# missing=sorted(set(alldays)-set(hist_df.time))
rangebreaks=[
# NOTE: Below values are bound (not single values), ie. hide x to y
dict(bounds=["sat", "mon"]), # hide weekends, eg. hide sat to before mon
dict(bounds=[22, 15.5], pattern="hour"), # hide hours outside of 9.30am-4pm
# dict(values=["2020-12-25", "2021-01-01"]) # hide holidays (Christmas and New Year's, etc)
]
fig.update_xaxes(rangebreaks=rangebreaks)
##START DASH
app = Dash(__name__)
## Define the title for the app
mytitle = dcc.Markdown('# Backtesting results')
button = html.Button('save static', id='save', n_clicks=0)
saved = html.Span('', id='saved')
textik1 = html.Div('''
Strategy:''' + state.name)
textik2 = html.Div('''
Tested period:'''+ self.bp_from.strftime("%d/%m/%Y, %H:%M:%S") + '-' + self.bp_to.strftime("%d/%m/%Y, %H:%M:%S"))
textik3 = html.Div('''
Stratvars:'''+ str(state.vars))
textik35 = html.Div('''
Resolution:'''+ str(state.timeframe) + "s rectype:" + str(state.rectype))
textik4 = html.Div('''
Started at:''' + self.backtest_start.strftime("%d/%m/%Y, %H:%M:%S") + " Duration:"+str(self.backtest_end-self.backtest_start))
textik5 = html.Div('''
Cash start:''' + str(self.cash_init)+ " Cash final" + str(self.cash))
textik55 = html.Div('''
Positions:''' + str(self.account))
textik6 = html.Div('''
Open orders:''' + str(len(self.open_orders)))
textik7 = html.Div('''
Trades:''' + str(len(self.trades)))
orders_title = dcc.Markdown('## Open orders')
trades_title = dcc.Markdown('## Trades')
## Define the graph
mygraph= dcc.Graph(id = "hlavni-graf", figure=fig)
open_orders_table = dash_table.DataTable(
id="orderstable",
data=open_orders_df.to_dict('records'),
columns=[{'id': c, 'name': c} for c in open_orders_df.columns],
sort_action="native",
row_selectable="single",
column_selectable=False,
fill_width = False,
filter_action = "native",
style_table={
'height': 500,
'overflowY': 'scroll'
},
style_header={
'backgroundColor': 'lightgrey',
'color': 'black'
},
style_data={
'backgroundColor': 'white',
'color': 'black'
},
style_cell={
'overflow': 'hidden',
'textOverflow': 'ellipsis',
'maxWidth': 220,
'minWidth': 5,
'width': 5
}
)
trades_table = dash_table.DataTable(
id="tradestable",
data=trade_df.to_dict('records'),
columns=[{'id': c, 'name': c} for c in trade_df.columns],
sort_action="native",
row_selectable="single",
column_selectable=False,
fill_width = False,
filter_action = "native",
style_table={
'height': 500,
'overflowY': 'scroll'
},
style_header={
'backgroundColor': 'lightgrey',
'color': 'black'
},
style_data={
'backgroundColor': 'white',
'color': 'black'
},
style_cell={
'overflow': 'hidden',
'textOverflow': 'ellipsis',
'maxWidth': 220,
'minWidth': 5,
'width': 5
}
# page_size=15
)
@app.callback(Output("tradestable", "style_data_conditional"),
Input("hlavni-graf", "hoverData"))
def highlight(hoverData):
#print(hoverData)
if hoverData is None:
return None
try:
row = hoverData["points"][0]["customdata"]
except KeyError:
return None
#print(row)
#print({"if": {"filter_query": "{{orderid}}={}".format(row)}, "backgroundColor": "lightgrey"})
return [
{"if": {"filter_query": "{{orderid}}={}".format(row)}, "backgroundColor": "lightgrey"}
]
@app.callback(Output("orderstable", "style_data_conditional"),
Input("hlavni-graf", "hoverData"))
def highlight(hoverData):
#print(hoverData)
if hoverData is None:
return None
try:
row = hoverData["points"][0]["customdata"]
except KeyError:
return None
#print(row)
#print({"if": {"filter_query": "{{orderid}}={}".format(row)}, "backgroundColor": "lightgrey"})
return [
{"if": {"filter_query": "{{orderid}}={}".format(row)}, "backgroundColor": "lightgrey"}
]
@app.callback(
Output('saved', 'children'),
Input('save', 'n_clicks'),
)
def save_result(n_clicks):
if n_clicks == 0:
return 'not saved'
else:
bt_dir = DATADIR + "/backtestresults/" + self.symbol + self.bp_from.strftime("%d-%m-%y-%H-%M-%S") + ' ' + self.bp_to.strftime("%d-%m-%y-%H-%M-%S") + ' ' + str(datetime.now().microsecond)
make_static(f'http://127.0.0.1:{port}/', bt_dir)
return 'saved'
## Customize your layout
app.layout = dbc.Container([mytitle,button,saved, textik1, textik2, textik3, textik35, textik4, textik5, textik55, textik6,textik7, mygraph, trades_title, trades_table, orders_title, open_orders_table])
port = 9050
print("Backtest FINSIHED"+str(self.backtest_end-self.backtest_start))
threading.Thread(target=lambda: app.run(port=port, debug=False, use_reloader=False)).start()
#app.run_server(debug=False, port = port)
print("tady se spouští server")
print("Jedeme dal?")

View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

100
v2realbot/common/model.py Normal file
View File

@ -0,0 +1,100 @@
from uuid import UUID, uuid4
from alpaca.trading.enums import OrderSide, OrderStatus, TradeEvent, OrderClass, OrderType, TimeInForce
#from utils import AttributeDict
from rich import print
from typing import Any, Optional, List, Union
from datetime import datetime, date
from pydantic import BaseModel
from v2realbot.enums.enums import Mode, Account
#tu samou variantu pak UpdateStrategyInstanceWhileRunning
#only those that can be changed UUID id prijde v parametru
# @app.put("/api/v1/users/{id}")
# async def update_user(user_update: UpdateUser, id: UUID):
# for user in db:
# if user.id == id:
# 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
# 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}")
#persisted object in pickle
class StrategyInstance(BaseModel):
id: Optional[UUID | str | None] = None
id2: int
name: str
symbol: str
class_name: str
script: str
open_rush: int = 0
close_rush: int = 0
stratvars_conf: str
add_data_conf: str
note: Optional[str]
history: Optional[str]
class RunRequest(BaseModel):
id: UUID
account: Account
mode: Mode
debug: bool = False
bt_from: datetime = None
bt_to: datetime = None
cash: int = 100000
class RunnerView(BaseModel):
id: UUID
run_started: Optional[datetime] = None
run_mode: Mode
run_account: Account
run_stopped: Optional[datetime] = None
run_paused: Optional[datetime] = None
#Running instance - not persisted
class Runner(BaseModel):
id: UUID
run_started: Optional[datetime] = None
run_mode: Mode
run_account: Account
run_stopped: Optional[datetime] = None
run_paused: Optional[datetime] = None
run_thread: Optional[object] = None
run_instance: Optional[object] = None
run_pause_ev: Optional[object] = None
run_stop_ev: Optional[object] = None
class Order(BaseModel):
id: UUID
submitted_at: datetime
filled_at: Optional[datetime]
canceled_at: Optional[datetime]
symbol: str
qty: int
status: OrderStatus
order_type: OrderType
filled_qty: Optional[int]
filled_avg_price: Optional[float]
side: OrderSide
limit_price: Optional[float]
class TradeUpdate(BaseModel):
event: Union[TradeEvent, str]
execution_id: Optional[UUID]
order: Order
timestamp: datetime
position_qty: Optional[float]
price: Optional[float]
qty: Optional[float]
value: Optional[float]
cash: Optional[float]
pos_avg_price: Optional[float]
# class Trade(BaseModel):
# order: Order
# value: float

100
v2realbot/conf.toml Normal file
View File

@ -0,0 +1,100 @@
[general]
general_attributtes = true
ping_time = 1200
#V1 na BAC
[[strategies]]
name = "V1 na BAC"
symbol = "BAC"
script = "ENTRY_backtest_strategyVykladaci"
class = "StrategyOrderLimitVykladaci"
open_rush = 0
close_rush = 0
[stratvars]
maxpozic = 200
chunk = 10
MA = 6
Trend = 5
profit = 0.02
lastbuyindex=-6
pendingbuys={}
limitka = "None"
jevylozeno=0
vykladka=5
curve = [0.01, 0.01, 0.01, 0.0, 0.02, 0.02, 0.01,0.01, 0.01,0.03, 0.01, 0.01, 0.01,0.04, 0.01,0.01, 0.01,0.05, 0.01,0.01, 0.01,0.01, 0.06,0.01, 0.01,0.01, 0.01]
blockbuy = 0
ticks2reset = 0.04
[[add_data]]
symbol="BAC"
rectype= "bar"
timeframe=5
update_ltp=true
align="round"
mintick=0
minsize=100
exthours=false
#D2 na C
[[strategies]]
name = "D2 na C"
script = "ENTRY_backtest_strategyKOKA-ok"
class = "StrategyOrderLimitKOKA"
symbol = "C"
open_rush = 0
close_rush = 0
[strategies.stratvars]
maxpozic = 200
chunk = 10
MA = 4
Trend = 4
profit = 0.01
lastbuyindex=-6
pendingbuys={}
limitka = "None"
[[strategies.add_data]]
symbol="C"
rectype="bar"
timeframe=10
update_ltp=true
align="round"
mintick=0
minsize=100
exthours=false
#V3 na EPD
[[strategies]]
name = "V3 na EPD"
symbol = "EPD"
script = "ENTRY_backtest_strategyVykladaci"
class = "StrategyOrderLimitVykladaci"
open_rush = 0
close_rush = 0
[strategies.stratvars]
maxpozic = 200
chunk = 10
MA = 4
Trend = 4
profit = 0.02
lastbuyindex=-6
pendingbuys={}
limitka = "None"
jevylozeno=0
vykladka=5
curve = [0.01, 0.01, 0.01,0.01, 0.02, 0.01,0.01, 0.01,0.03, 0.01, 0.01, 0.01,0.04, 0.01,0.01, 0.01,0.05, 0.01,0.01, 0.01,0.01, 0.06,0.01, 0.01,0.01, 0.01]
blockbuy = 0
ticks2reset = 0.04
[[strategies.add_data]]
symbol="EPD"
rectype="bar"
timeframe=15
update_ltp=true
align="round"
mintick=0
minsize=100
exthours=false

74
v2realbot/config.py Normal file
View File

@ -0,0 +1,74 @@
from alpaca.data.enums import DataFeed
from v2realbot.enums.enums import Mode, Account
from appdirs import user_data_dir
DATA_DIR = user_data_dir("v2realbot")
#BT DELAYS
""""
LATENCY DELAYS for LIVE eastcoast
.000 trigger - last_trade_time (.4246266)
+.020 vstup do strategie a BUY (.444606)
+.023 submitted (.469198)
+.008 filled (.476695552)
+.023 fill not(.499888)
"""
#TODO změnit názvy delay promennych vystizneji a obecneji
class BT_DELAYS:
trigger_to_strat: float = 0.020
strat_to_sub: float = 0.023
sub_to_fill: float = 0.008
fill_to_not: float = 0.023
#doplnit dle live
limit_order_offset: float = 0
class Keys:
def __init__(self, api_key, secret_key, paper, feed) -> None:
self.API_KEY = api_key
self.SECRET_KEY = secret_key
self.PAPER = paper
self.FEED = feed
# podle modu (PAPER, LIVE) vrati objekt
# obsahujici klice pro pripojeni k alpace
def get_key(mode: Mode, account: Account):
if mode not in [Mode.PAPER, Mode.LIVE]:
print("has to be LIVE or PAPER only")
return None
dict = globals()
try:
API_KEY = dict[str.upper(str(account.value)) + "_" + str.upper(str(mode.value)) + "_API_KEY" ]
SECRET_KEY = dict[str.upper(str(account.value)) + "_" + str.upper(str(mode.value)) + "_SECRET_KEY" ]
PAPER = dict[str.upper(str(account.value)) + "_" + str.upper(str(mode.value)) + "_PAPER" ]
FEED = dict[str.upper(str(account.value)) + "_" + str.upper(str(mode.value)) + "_FEED" ]
return Keys(API_KEY, SECRET_KEY, PAPER, FEED)
except KeyError:
print("Not valid combination to get keys for", mode, account)
return 0
#strategy instance main loop heartbeat
HEARTBEAT_TIMEOUT=5
WEB_API_KEY="david"
#PRIMARY PAPER
ACCOUNT1_PAPER_API_KEY = 'PKGGEWIEYZOVQFDRY70L'
ACCOUNT1_PAPER_SECRET_KEY = 'O5Kt8X4RLceIOvM98i5LdbalItsX7hVZlbPYHy8Y'
ACCOUNT1_PAPER_MAX_BATCH_SIZE = 1
ACCOUNT1_PAPER_PAPER = True
ACCOUNT1_PAPER_FEED = DataFeed.SIP
#PRIMARY LIVE
ACCOUNT1_LIVE_API_KEY = 'AKB5HD32LPDZC9TPUWJT'
ACCOUNT1_LIVE_SECRET_KEY = 'Xq1wPSNOtwmlMTAd4cEmdKvNDgfcUYfrOaCccaAs'
ACCOUNT1_LIVE_MAX_BATCH_SIZE = 1
ACCOUNT1_LIVE_PAPER = False
ACCOUNT1_LIVE_FEED = DataFeed.SIP
#SECONDARY PAPER
ACCOUNT2_PAPER_API_KEY = 'PKQEAAJTVC72SZO3CT3R'
ACCOUNT2_PAPER_SECRET_KEY = 'mqdftzGJlJdvUjdsuQynAURCHRwAI0a8nhJy8nyz'
ACCOUNT2_PAPER_MAX_BATCH_SIZE = 1
ACCOUNT2_PAPER_PAPER = True
ACCOUNT2_PAPER_FEED = DataFeed.IEX

View File

View File

@ -0,0 +1,317 @@
from typing import Any, List
from uuid import UUID, uuid4
import pickle
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account
from v2realbot.common.model import StrategyInstance, Runner, RunRequest
from v2realbot.utils.utils import AttributeDict, zoneNY, dict_replace_value, Store, parse_toml_string
from datetime import datetime
from threading import Thread, current_thread, Event, enumerate
import importlib
from queue import Queue
db = Store()
def get_all_threads():
res = str(enumerate())
if len(res) > 0:
return (0, res)
else:
return (-2, "not found")
def get_all_runners():
if len(db.runners) > 0:
print(db.runners)
return (0, db.runners)
else:
return (0, [])
def get_all_stratins():
if len(db.stratins) > 0:
return (0, db.stratins)
else:
return (0, [])
def get_stratin(id: UUID):
for i in db.stratins:
if str(i.id) == str(id):
return (0, i)
return (-2, "not found")
def get_runner(id: UUID):
for i in db.runners:
if str(i.id) == str(id):
return (0, i)
return (-2, "not found")
def create_stratin(si: StrategyInstance):
#validate toml
res, stp = parse_toml_string(si.stratvars_conf)
if res < 0:
return (-1,"stratvars invalid")
res, adp = parse_toml_string(si.add_data_conf)
if res < 0:
return (-1, "None")
si.id = uuid4()
print(si)
db.stratins.append(si)
db.save()
#print(db.stratins)
return (0,si.id)
def modify_stratin(si: StrategyInstance, id: UUID):
#validate toml if fields exists
if is_stratin_running(id):
return (-1, "strat is running, use modify_stratin_running")
res, stp = parse_toml_string(si.stratvars_conf)
if res < 0:
return (-1, "stratvars invalid")
res, adp = parse_toml_string(si.add_data_conf)
if res < 0:
return (-1, "add data conf invalid")
for i in db.stratins:
if str(i.id) == str(id):
print("removing",i)
db.stratins.remove(i)
print("adding",si)
db.stratins.append(si)
print(db.stratins)
db.save()
return (0, i.id)
return (-2, "not found")
def delete_stratin(id: UUID):
if is_stratin_running(id=str(id)):
return (-1, "Strategy Instance is running " + str(id))
for i in db.stratins:
if str(i.id) == str(id):
db.stratins.remove(i)
db.save()
print(db.stratins)
return (0, i.id)
return (-2, "not found")
def inject_stratvars(id: UUID, stratvars_parsed: AttributeDict):
for i in db.runners:
if str(i.id) == str(id):
i.run_instance.state.vars = AttributeDict(stratvars_parsed["stratvars"])
i.run_instance.stratvars = AttributeDict(stratvars_parsed["stratvars"])
return 0
return -2
#allows change of set of parameters that are possible to change while it is running
#also injects those parameters to instance
def modify_stratin_running(si: StrategyInstance, id: UUID):
#validate toml
res,stp = parse_toml_string(si.stratvars_conf)
if res < 0:
return (-1, "stratvars invalid")
for i in db.stratins:
if str(i.id) == str(id):
if not is_stratin_running(id=str(id)):
return (-1, "not running")
i.id2 = si.id2
i.name = si.name
i.open_rush = si.open_rush
i.stratvars_conf = si.stratvars_conf
i.note = si.note
i.history = si.history
db.save()
#TODO reload running strat
print(stp)
print("starting injection", stp)
res = inject_stratvars(id=si.id, stratvars_parsed=stp)
if res < 0:
print("ajajaj inject se nepovedl")
return(-3, "inject failed")
return (0, i.id)
return (-2, "not found")
#controller.reload_params(si)
##enable realtime chart - inject given queue for strategy instance
##webservice listens to this queue
async def stratin_realtime_on(id: UUID, rtqueue: Queue):
for i in db.runners:
if str(i.id) == str(id):
i.run_instance.rtqueue = rtqueue
print("RT QUEUE added")
return 0
print("ERROR NOT FOUND")
return -2
async def stratin_realtime_off(id: UUID):
for i in db.runners:
if str(i.id) == str(id):
i.run_instance.rtqueue = None
print("RT QUEUE removed")
return 0
print("ERROR NOT FOUND")
return -2
##controller (run_stratefy, pause, stop, reload_params)
def pause_stratin(id: UUID):
for i in db.runners:
print(i.id)
if str(i.id) == id:
if i.run_pause_ev.is_set():
i.run_pause_ev.clear()
i.run_paused = None
print("Unpaused")
return (0, "unpaused runner " + str(i.id))
print("pausing runner", i.id)
i.run_pause_ev.set()
i.run_paused = datetime.now().astimezone(zoneNY)
return (0, "paused runner " + str(i.id))
print("no ID found")
return (-1, "not running instance found")
def stop_stratin(id: UUID = None):
chng = []
for i in db.runners:
#print(i['id'])
if id is None or str(i.id) == id:
chng.append(i.id)
print("Sending STOP signal to Runner", i.id)
#just sending the signal, update is done in stop after plugin
i.run_stop_ev.set()
# i.run_stopped = datetime.now().astimezone(zoneNY)
# i.run_thread = None
# i.run_instance = None
# i.run_pause_ev = None
# i.run_stop_ev = None
# #stratins.remove(i)
if len(chng) > 0:
return (0, "Sent STOP signal to those" + str(chng))
else:
return (-2, "not found" + str(id))
def is_stratin_running(id: UUID):
for i in db.runners:
if str(i.id) == str(id):
if i.run_started is not None and i.run_stopped is None:
return True
return False
def save_history(id: UUID, st: object, runner: Runner, reason: str = None):
for i in db.stratins:
if str(i.id) == str(id):
i.history += "START:"+str(runner.run_started)+"STOP:"+str(runner.run_stopped)+"ACC:"+runner.run_account.value+"M:"+runner.run_mode.value+"PROFIT:XX" + reason + "<BR>"
#i.history += str(runner.__dict__)+"<BR>"
db.save()
#Capsule to run the thread in. Needed in order to update db after strat ends for any reason#
def capsule(target: object, db: object):
#TODO zde odchytit pripadnou exceptionu a zapsat do history
#cil aby padnuti jedne nezpusobilo pad enginu
try:
target.start()
print("Strategy instance stopped. Update runners")
reason = "SHUTDOWN OK"
except Exception as e:
reason = "SHUTDOWN Exception:" + str(e)
finally:
# remove runners after thread is stopped and save results to stratin history
for i in db.runners:
if i.run_instance == target:
i.run_stopped = datetime.now().astimezone(zoneNY)
i.run_thread = None
i.run_instance = None
i.run_pause_ev = None
i.run_stop_ev = None
#ukladame radek do historie (pozdeji refactor)
save_history(id=i.id, st=target, runner=i, reason=reason)
#mazeme runner po skonceni instance
db.runners.remove(i)
print("Runner STOPPED")
def run_stratin(id: UUID, runReq: RunRequest):
if runReq.mode == Mode.BT:
if runReq.bt_from is None:
return (-1, "start date required for BT")
if runReq.bt_to is None:
runReq.bt_to = datetime.now().astimezone(zoneNY)
print("hodnota ID pred",id)
#volani funkce instantiate_strategy
for i in db.stratins:
if str(i.id) == str(id):
try:
if is_stratin_running(id=id):
return(-1, "already running")
#validate toml
res, stp = parse_toml_string(i.stratvars_conf)
if res < 0:
return (-1, "stratvars invalid")
res, adp = parse_toml_string(i.add_data_conf)
if res < 0:
return (-1, "add data conf invalid")
print("jsme uvnitr")
id = uuid4()
name = i.name
symbol = i.symbol
open_rush = i.open_rush
close_rush = i.close_rush
#do budoucna vylepsit konfiguraci, udelat na frontendu jedno pole config
#obsahujici cely toml dane strategie
#nyni predpokladame, ze stratvars a add_data sloupce v gui obsahuji
#dany TOML element
try:
stratvars = AttributeDict(stp["stratvars"])
except KeyError:
return (-1, "stratvars musi obsahovat element [stratvars]")
classname = i.class_name
script = "v2realbot."+i.script
pe = Event()
se = Event()
import_script = importlib.import_module(script)
next = getattr(import_script, "next")
init = getattr(import_script, "init")
my_module = importlib.import_module("v2realbot.strategy."+classname)
StrategyClass = getattr(my_module, classname)
#instance strategie
instance = StrategyClass(name= name,
symbol=symbol,
account=runReq.account,
next=next,
init=init,
stratvars=stratvars,
open_rush=open_rush, close_rush=close_rush, pe=pe, se=se)
print("instance vytvorena", instance)
#set mode
if runReq.mode == Mode.LIVE or runReq.mode == Mode.PAPER:
instance.set_mode(mode=runReq.mode, debug = runReq.debug)
else:
instance.set_mode(mode = Mode.BT,
debug = runReq.debug,
start = runReq.bt_from.astimezone(zoneNY),
end = runReq.bt_to.astimezone(zoneNY),
cash=runReq.cash)
##add data streams
for st in adp["add_data"]:
print("adding stream", st)
instance.add_data(**st)
print("Starting strategy", instance.name)
#vlakno = Thread(target=instance.start, name=instance.name)
#pokus na spusteni v kapsli, abychom po skonceni mohli updatnout stratin
vlakno = Thread(target=capsule, args=(instance,db), name=instance.name)
vlakno.start()
print("Spuštěna", instance.name)
##storing the attributtes - pozor pri stopu je zase odstranit
runner = Runner(id = i.id,
run_started = datetime.now(zoneNY),
run_pause_ev = pe,
run_stop_ev = se,
run_thread = vlakno,
run_account = runReq.account,
run_mode = runReq.mode,
run_instance = instance)
db.runners.append(runner)
print(db.runners)
print(i)
print(enumerate())
return (0, i.id)
except Exception as e:
return (-2, "Exception: "+str(e))
return (-2, "not found")

View File

@ -0,0 +1,27 @@
from strategy import MyStrategy, StrategyState
from enums import RecordType, StartBarAlign
from config import API_KEY, SECRET_KEY, MAX_BATCH_SIZE, PAPER
from indicators import ema
from rich import print
def next(data, state: StrategyState):
print("next")
print(state.variables.MA)
print(state.variables.maxpozic)
print(data)
print(state.oe.pos())
def init(state: StrategyState):
print("init - zatim bez data")
print(state.oe.symbol)
print(state.oe.pos())
print()
def main():
stratvars = dict(maxpozic = 10, chunk = 1, MA = 3, Trend = 4,profit = 0.01)
s = MyStrategy("TSLA",paper=PAPER, next=next, init=init, stratvars=stratvars)
s.add_data(symbol="TSLA",rectype=RecordType.TRADE,timeframe=5,filters=None,update_ltp=True,align=StartBarAlign.ROUND,mintick=0)
s.start()
if __name__ == "__main__":
main()

View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

47
v2realbot/enums/enums.py Normal file
View File

@ -0,0 +1,47 @@
from enum import Enum
from alpaca.trading.enums import OrderSide, OrderStatus
class Order:
def __init__(self, id: str, status: OrderStatus, side: OrderSide, symbol: str, qty: int, limit_price: float = None, filled_qty: int = 0, filled_avg_price: float = 0, filled_time: float = None) -> None:
self.id = id
self.status = status
self.side = side
self.symbol = symbol
self.qty = qty
self.filled_qty = filled_qty
self.filled_avg_price = filled_avg_price
self.filled_time = filled_time
self.limit_price = limit_price
class Account(Enum):
"""
Accounts - keys to config
"""
ACCOUNT1 = "ACCOUNT1"
ACCOUNT2 = "ACCOUNT2"
class RecordType(Enum):
"""
Represents output of aggregator
"""
BAR = "bar"
CBAR = "continuosbar"
TRADE = "trade"
class Mode(Enum):
"""
LIVE or BT
"""
PAPER = "paper"
LIVE = "live"
BT = "backtest"
class StartBarAlign(Enum):
"""
Represents first bar start time alignement according to timeframe
ROUND = bar starts at 0,5,10 (for 5s timeframe)
RANDOM = first bar starts when first trade occurs
"""
ROUND = "round"
RANDOM = "random"

View File

View File

@ -0,0 +1,36 @@
import tulipy as ti
import numpy as np
import pandas as pd
from collections import deque
import typing
def ema(data, period: int = 50, use_series=False):
if check_series(data):
use_series = True
data = convert_to_numpy(data)
ema = ti.ema(data, period=period)
return pd.Series(ema) if use_series else ema
def sma(data, period: int = 50, use_series=False):
"""
Finding the moving average of a dataset
Args:
data: (list) A list containing the data you want to find the moving average of
period: (int) How far each average set should be
"""
if check_series(data):
use_series = True
data = convert_to_numpy(data)
sma = ti.sma(data, period=period)
return pd.Series(sma) if use_series else sma
def convert_to_numpy(data):
if isinstance(data, list) or isinstance(data, deque):
return np.fromiter(data, float)
elif isinstance(data, pd.Series):
return data.to_numpy()
return data
def check_series(data):
return isinstance(data, pd.Series)

View File

@ -0,0 +1,119 @@
"""
Moving average function utils
Copyright (C) 2021 Brandon Fan
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
#inspirovat se, pripadne vyzkouset i TAlib
from typing import Any
import pandas as pd
import tulipy as ti
def convert_to_numpy(data: Any):
if isinstance(data, list) or isinstance(data, deque):
return np.fromiter(data, float)
elif isinstance(data, pd.Series):
return data.to_numpy()
return data
def check_series(data: Any):
return isinstance(data, pd.Series)
def ema(data: Any, period: int = 50, use_series=False) -> Any:
if check_series(data):
use_series = True
data = convert_to_numpy(data)
ema = ti.ema(data, period=period)
return pd.Series(ema) if use_series else ema
def vwma(data: Any, volume_data: Any, period: int = 50, use_series=False) -> Any:
if check_series(data):
use_series = True
data = convert_to_numpy(data)
volume_data = convert_to_numpy(volume_data).astype(float)
vwma = ti.vwma(data, volume_data, period=period)
return pd.Series(vwma) if use_series else vwma
def wma(data: Any, period: int = 50, use_series=False) -> Any:
if check_series(data):
use_series = True
data = convert_to_numpy(data)
wma = ti.wma(data, period)
return pd.Series(wma) if use_series else wma
def zlema(data: Any, period: int = 50, use_series=False) -> Any:
if check_series(data):
use_series = True
data = convert_to_numpy(data)
zlema = ti.zlema(data, period)
return pd.Series(zlema) if use_series else zlema
def sma(data: Any, period: int = 50, use_series=False) -> Any:
"""
Finding the moving average of a dataset
Args:
data: (list) A list containing the data you want to find the moving average of
period: (int) How far each average set should be
"""
if check_series(data):
use_series = True
data = convert_to_numpy(data)
sma = ti.sma(data, period=period)
return pd.Series(sma) if use_series else sma
def hma(data: Any, period: int = 50, use_series=False) -> Any:
if check_series(data):
use_series = True
data = convert_to_numpy(data)
hma = ti.hma(data, period)
return pd.Series(hma) if use_series else hma
def kaufman_adaptive_ma(data: Any, period: int = 50, use_series=False) -> Any:
if check_series(data):
use_series = True
data = convert_to_numpy(data)
kama = ti.kama(data, period)
return pd.Series(kama) if use_series else kama
def trima(data: Any, period: int = 50, use_series=False) -> Any:
if check_series(data):
use_series = True
data = convert_to_numpy(data)
trima = ti.trima(data, period)
return pd.Series(trima) if use_series else trima
def macd(data: Any, short_period: int = 12, long_period: int = 26, signal_period: int = 9, use_series=False) -> Any:
if check_series(data):
use_series = True
data = convert_to_numpy(data)
macd, macd_signal, macd_histogram = ti.macd(data, short_period, long_period, signal_period)
if use_series:
df = pd.DataFrame({'macd': macd, 'macd_signal': macd_signal, 'macd_histogram': macd_histogram})
return df
return macd, macd_signal, macd_histogram

View File

Some files were not shown because too many files have changed in this diff Show More