retreat commit
This commit is contained in:
7
.gitignore
vendored
7
.gitignore
vendored
@ -8,6 +8,7 @@
|
|||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
*.py[cod]
|
||||||
|
*.pyc
|
||||||
|
|
||||||
# C extensions
|
# C extensions
|
||||||
*.so
|
*.so
|
||||||
@ -32,3 +33,9 @@ share/python-wheels/
|
|||||||
*.egg
|
*.egg
|
||||||
MANIFEST
|
MANIFEST
|
||||||
strat.log
|
strat.log
|
||||||
|
v2realbot/__pycache__/
|
||||||
|
v2realbot/.DS_Store
|
||||||
|
v2realbot/static/.DS_Store
|
||||||
|
v2realbot/static/js/.DS_Store
|
||||||
|
v2realbot/static/js/libs/.DS_Store
|
||||||
|
v2realbot/strategyblocks/activetrade/.DS_Store
|
||||||
|
|||||||
16
.vscode/launch.json
vendored
16
.vscode/launch.json
vendored
@ -1,7 +1,4 @@
|
|||||||
{
|
{
|
||||||
// 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",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
@ -10,8 +7,19 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${file}",
|
"program": "${file}",
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"env": {"PYTHONPATH": "${workspaceFolder}:${workspaceFolder}/bld"},
|
"env": {
|
||||||
|
"PYTHONPATH": "${workspaceFolder}:${workspaceFolder}/bld"
|
||||||
|
},
|
||||||
"console": "integratedTerminal",
|
"console": "integratedTerminal",
|
||||||
|
"justMyCode": true,
|
||||||
|
"python": "${command:python.interpreterPath}",
|
||||||
|
"internalConsoleOptions": "openOnSessionStart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Python: File",
|
||||||
|
"type": "python",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${file}",
|
||||||
"justMyCode": true
|
"justMyCode": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -2,5 +2,6 @@
|
|||||||
"python.analysis.logLevel": "Trace",
|
"python.analysis.logLevel": "Trace",
|
||||||
"terminal.integrated.env.osx": {
|
"terminal.integrated.env.osx": {
|
||||||
"PYTHONPATH": "${workspaceFolder}/"
|
"PYTHONPATH": "${workspaceFolder}/"
|
||||||
}
|
},
|
||||||
|
"python.analysis.typeCheckingMode": "off"
|
||||||
}
|
}
|
||||||
39
testy/ml/numpybasics.py
Normal file
39
testy/ml/numpybasics.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import numpy as np
|
||||||
|
|
||||||
|
a = np.arange(20).reshape(2,2,5)
|
||||||
|
print(a)
|
||||||
|
|
||||||
|
#b = np.zeros((3,4))
|
||||||
|
b = np.arange(12).reshape(3,4)
|
||||||
|
print(b)
|
||||||
|
#max z kazdeho sloupce
|
||||||
|
c = np.max(b, axis=0)
|
||||||
|
#suma kazdeho radku
|
||||||
|
c = np.sum(b, axis=1)
|
||||||
|
c = c.reshape(3,1)
|
||||||
|
#sumu pridam na konec kazdeho radku, tzn.pripojim sloupce (horizontalne)
|
||||||
|
d=np.hstack((b,c))
|
||||||
|
print(d)
|
||||||
|
|
||||||
|
#indexovani booleanem
|
||||||
|
e = np.arange(12).reshape(3,4)
|
||||||
|
f = e < 5
|
||||||
|
print(e,f)
|
||||||
|
print(e[f])
|
||||||
|
#vsechny mensi nez 5 se stanou 0
|
||||||
|
e[e<5] = 0
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
|
||||||
|
# c = np.ones((2,2))
|
||||||
|
# c = c.reshape(1,4)
|
||||||
|
# print(c)
|
||||||
|
# print(c*b)
|
||||||
|
|
||||||
|
# d = np.arange(4).reshape(2,2)
|
||||||
|
# e = d.copy()
|
||||||
|
|
||||||
|
# print("d",d)
|
||||||
|
# print("e",e)
|
||||||
|
# print(d*e)
|
||||||
|
# print(d@e)
|
||||||
37
testy/ml/numpyslicingtensors.py
Normal file
37
testy/ml/numpyslicingtensors.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import numpy as np
|
||||||
|
|
||||||
|
t = np.array([[[1,2,3,4,5], [2,2,2,2,2]],
|
||||||
|
|
||||||
|
[[3,3,3,3,3], [4,4,4,4,4]],
|
||||||
|
|
||||||
|
[[5,5,5,5,5], [6,6,6,6,6]]])
|
||||||
|
|
||||||
|
print(t.shape, t.ndim, t.dtype)
|
||||||
|
|
||||||
|
print(t[0:2].shape)
|
||||||
|
|
||||||
|
|
||||||
|
#nasledujici je totozne
|
||||||
|
a = t[:2]
|
||||||
|
b = t[0:2, :, :]
|
||||||
|
c = t[0:2, 0:2, 0:5]
|
||||||
|
|
||||||
|
#posledni dve cisla kazdeho elementu tensoru 1
|
||||||
|
a = t[1, :, 3:]
|
||||||
|
|
||||||
|
#prostredni 3 cisla z kazdeho elementu
|
||||||
|
a = t[:, :, 1:-1]
|
||||||
|
# print(a==b)
|
||||||
|
print(a)
|
||||||
|
# print(b)
|
||||||
|
# print(c)
|
||||||
|
|
||||||
|
print(t.reshape((6,5)))
|
||||||
|
print(t.reshape((30)))
|
||||||
|
print(t.reshape((30,1)))
|
||||||
|
print(np.transpose(t))
|
||||||
|
|
||||||
|
|
||||||
|
#operations
|
||||||
|
u =np.array([5,2,1,1,4])
|
||||||
|
print(t+u)
|
||||||
29
testy/ml/numpytrendcolumn.py
Normal file
29
testy/ml/numpytrendcolumn.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import numpy as np
|
||||||
|
|
||||||
|
y = np.arange(20).reshape(4,5)
|
||||||
|
print("y",y)
|
||||||
|
# y = y[1:5:2,]
|
||||||
|
y = y[::2,::2]
|
||||||
|
print("y",y)
|
||||||
|
|
||||||
|
|
||||||
|
# a = np.arange(30).reshape(-1,5)
|
||||||
|
|
||||||
|
# #pole_posunute o radek dopredu - future a
|
||||||
|
# fa = a.copy()
|
||||||
|
# fa = fa[1:]
|
||||||
|
# print("fa",fa)
|
||||||
|
|
||||||
|
# #acko orizneme vzadu - aby byly stejne dlouhe
|
||||||
|
# a = a[:-1]
|
||||||
|
# print(a)
|
||||||
|
# #a pak porovnáme jejich poslední sloupce a vysledek dáme jako další sloupec s 1 nebo 0
|
||||||
|
# #nicmene melo by to nejak jit i bez pomocného pole
|
||||||
|
# posl_sloupec=a[:,-1:]<fa[:,-1:]
|
||||||
|
# print(posl_sloupec)
|
||||||
|
# #sloupec 1/0 zda je hodnota nizsi nez hodnota o jeden radek vpredu
|
||||||
|
# #tak si muzu nadefinovat 1ky kdyz je rising for 5 bars - udealt funkcni
|
||||||
|
# a = np.hstack((a, posl_sloupec))
|
||||||
|
# print(a)
|
||||||
|
# #print(a[posl_sloupec>4])
|
||||||
|
|
||||||
@ -75,8 +75,8 @@ if res == 0:
|
|||||||
else:
|
else:
|
||||||
print("error",res,sada)
|
print("error",res,sada)
|
||||||
|
|
||||||
bars = sada["bars"]
|
# bars = sada["bars"]
|
||||||
indicators = sada["indicators"][0]
|
# indicators = sada["indicators"][0]
|
||||||
|
|
||||||
# Zakladni nastaveni
|
# Zakladni nastaveni
|
||||||
testlist_id = ""
|
testlist_id = ""
|
||||||
@ -86,11 +86,11 @@ indicator_features = ['samebarslope', 'fastslope','fsdelta', 'fastslope2', 'fsde
|
|||||||
features = ["time","high","low","volume","open","close", "trades", "vwap","samebarslope", "fastslope","fsdelta", "fastslope2", "fsdelta2"]
|
features = ["time","high","low","volume","open","close", "trades", "vwap","samebarslope", "fastslope","fsdelta", "fastslope2", "fsdelta2"]
|
||||||
#TODO toto je linearni prediction mod, dodelat podporu BINARY
|
#TODO toto je linearni prediction mod, dodelat podporu BINARY
|
||||||
#u binary bude target bud hotovy indikator a nebo jej vytvorit on the fly
|
#u binary bude target bud hotovy indikator a nebo jej vytvorit on the fly
|
||||||
target = 'vwap'
|
target = 'close'
|
||||||
#predict how many bars in the future
|
#predict how many bars in the future
|
||||||
target_steps = 5
|
target_steps = 5
|
||||||
name = "model1"
|
name = "model1"
|
||||||
seq = 10
|
seq = 2
|
||||||
epochs = 500
|
epochs = 500
|
||||||
|
|
||||||
features.sort()
|
features.sort()
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
102
v2realbot/LSTMevalrunner.py
Normal file
102
v2realbot/LSTMevalrunner.py
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
import numpy as np
|
||||||
|
from sklearn.preprocessing import StandardScaler
|
||||||
|
from sklearn.metrics import mean_squared_error
|
||||||
|
from sklearn.model_selection import train_test_split
|
||||||
|
import v2realbot.ml.mlutils as mu
|
||||||
|
from keras.layers import LSTM, Dense
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
from v2realbot.ml.ml import ModelML
|
||||||
|
from v2realbot.enums.enums import PredOutput, Source, TargetTRFM
|
||||||
|
from v2realbot.controller.services import get_archived_runner_details_byID, update_archive_detail
|
||||||
|
# from collections import defaultdict
|
||||||
|
# from operator import itemgetter
|
||||||
|
from joblib import load
|
||||||
|
|
||||||
|
#TODO - DO API
|
||||||
|
# v ml atomicke api pro evaluaci (runneru, batche)
|
||||||
|
# v services: model.add_vector_prediction_to_archrunner_as_new_indicator (vrátí v podstate obohacený archDetail) - nebo i ukládat do db? uvidime
|
||||||
|
# v rest api prevolani
|
||||||
|
# db support: zatim jen ciselnik modelu + jeho zakladni nastaveni, obrabeci api, load modelu zatim z file
|
||||||
|
|
||||||
|
cfg: ModelML = mu.load_model("model1", "0.1")
|
||||||
|
|
||||||
|
|
||||||
|
#EVALUATE SPECIFIC RUNNER - VECTOR BASED (toto dat do samostatne API pripadne pak udelat nadstavnu na batch a runners)
|
||||||
|
#otestuje model na neznamem runnerovi, seznamu runneru nebo batch_id
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
runner_id = "a38fc269-8df3-4374-9506-f0280d798854"
|
||||||
|
save_new_ind = True
|
||||||
|
source_data, target_data, rows_in_day = cfg.load_data(runners_ids=[runner_id])
|
||||||
|
|
||||||
|
if len(rows_in_day) > 1:
|
||||||
|
#pro vis se cela tato sluzba volat v loopu
|
||||||
|
raise Exception("Vytvareni indikatoru dostupne zatim jen pro jeden runner")
|
||||||
|
|
||||||
|
#scalujeme X
|
||||||
|
source_data = cfg.scalerX.fit_transform(source_data)
|
||||||
|
|
||||||
|
#tady si vyzkousim i skrz vice runneru
|
||||||
|
X_eval, y_eval, y_eval_ref = cfg.create_sequences(combined_data=source_data, target_data=target_data,remove_cross_sequences=True, rows_in_day=rows_in_day)
|
||||||
|
|
||||||
|
#toto nutne?
|
||||||
|
X_eval = np.array(X_eval)
|
||||||
|
y_eval = np.array(y_eval)
|
||||||
|
y_eval_ref = np.array(y_eval_ref)
|
||||||
|
#scaluji target - nemusis
|
||||||
|
#y_eval = cfg.scalerY.fit_transform(y_eval)
|
||||||
|
|
||||||
|
X_eval = cfg.model.predict(X_eval)
|
||||||
|
X_eval = cfg.scalerY.inverse_transform(X_eval)
|
||||||
|
print("po predikci x_eval shape", X_eval.shape)
|
||||||
|
|
||||||
|
#pokud mame dostupnou i target v runneru, pak pridame porovnavaci indikator
|
||||||
|
difference_mse = None
|
||||||
|
if len(y_eval) > 0:
|
||||||
|
#TODO porad to pliva 1 hodnotu
|
||||||
|
difference_mse = mean_squared_error(y_eval, X_eval,multioutput="raw_values")
|
||||||
|
|
||||||
|
print("ted mam tedy dva nove sloupce")
|
||||||
|
print("X_eval", X_eval.shape)
|
||||||
|
if difference_mse is not None:
|
||||||
|
print("difference_mse", difference_mse.shape)
|
||||||
|
print(f"zplostime je, dopredu pridame {cfg.input_sequences-1} a dozadu nic")
|
||||||
|
#print(f"a melo by nam to celkem dat {len(bars['time'])}")
|
||||||
|
#tohle pak nejak doladit, ale vypada to good
|
||||||
|
#plus do druheho indikatoru pridat ten difference_mse
|
||||||
|
|
||||||
|
#TODO jeste je posledni hodnota predikce nejak OFF (2.52... ) - podivat se na to
|
||||||
|
#TODO na produkci srovnat se skutecnym BT predictem (mozna zde bude treba seq-1) -
|
||||||
|
# prvni predikce nejspis uz bude na desítce
|
||||||
|
ind_pred = list(np.concatenate([np.zeros(cfg.input_sequences-1), X_eval.ravel()]))
|
||||||
|
print(ind_pred)
|
||||||
|
print(len(ind_pred))
|
||||||
|
print("tada")
|
||||||
|
#ted k nim pridame
|
||||||
|
|
||||||
|
if save_new_ind:
|
||||||
|
#novy ind ulozime do archrunnera (na produkci nejspis jen show)
|
||||||
|
res, sada = get_archived_runner_details_byID(runner_id)
|
||||||
|
if res == 0:
|
||||||
|
print("ok")
|
||||||
|
else:
|
||||||
|
print("error",res,sada)
|
||||||
|
raise Exception(f"error loading runner {runner_id} : {res} {sada}")
|
||||||
|
|
||||||
|
sada["indicators"][0]["pred_added"] = ind_pred
|
||||||
|
|
||||||
|
req = update_archive_detail(runner_id, sada)
|
||||||
|
print(f"indicator pred_added was ADDED to {runner_id}")
|
||||||
|
|
||||||
|
|
||||||
|
# Plot the predicted vs. actual
|
||||||
|
plt.plot(y_eval, label='Target')
|
||||||
|
plt.plot(X_eval, label='Predicted')
|
||||||
|
#TODO zde nejak vymyslet jinou pricelinu - jako lightweight chart
|
||||||
|
if difference_mse is not None:
|
||||||
|
plt.plot(difference_mse, label='diference')
|
||||||
|
plt.plot(y_eval_ref, label='reference column - vwap')
|
||||||
|
plt.plot()
|
||||||
|
plt.legend()
|
||||||
|
plt.show()
|
||||||
@ -2,331 +2,276 @@ import numpy as np
|
|||||||
from sklearn.preprocessing import StandardScaler
|
from sklearn.preprocessing import StandardScaler
|
||||||
from sklearn.metrics import mean_squared_error
|
from sklearn.metrics import mean_squared_error
|
||||||
from sklearn.model_selection import train_test_split
|
from sklearn.model_selection import train_test_split
|
||||||
from keras.models import Sequential, load_model
|
import v2realbot.ml.mlutils as mu
|
||||||
from keras.layers import LSTM, Dense
|
from keras.layers import LSTM, Dense
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
from v2realbot.controller.services import get_archived_runner_details_byID
|
from v2realbot.ml.ml import ModelML
|
||||||
from v2realbot.common.model import RunArchiveDetail
|
from v2realbot.enums.enums import PredOutput, Source, TargetTRFM
|
||||||
from v2realbot.config import DATA_DIR
|
# from collections import defaultdict
|
||||||
from v2realbot.utils.utils import slice_dict_lists
|
# from operator import itemgetter
|
||||||
from collections import defaultdict
|
from joblib import load
|
||||||
from operator import itemgetter
|
|
||||||
from joblib import dump, load
|
|
||||||
|
|
||||||
|
# region Notes
|
||||||
|
|
||||||
#ZAKLAD PRO TRAINING SCRIPT na vytvareni model
|
#ZAKLAD PRO TRAINING SCRIPT na vytvareni model u
|
||||||
# TODO
|
# TODO
|
||||||
# podpora pro BINARY TARGET
|
# podpora pro BINARY TARGET
|
||||||
# podpora hyperpamaetru (activ.funkce sigmoid atp.)
|
# podpora hyperpamaetru (activ.funkce sigmoid atp.)
|
||||||
# udelat vsechny config vars do cfg objektu
|
|
||||||
# vyuzit distribuovane prostredi - nebo aspon vlastni VM
|
# vyuzit distribuovane prostredi - nebo aspon vlastni VM
|
||||||
# dopracovat identifikatory typu lastday close, todays open atp.
|
# dopracovat denni identifikatory typu lastday close, todays open atp.
|
||||||
# random SEARCG a grid search
|
# random SEARCH a grid search
|
||||||
# udelat nejaka model metadata (napr, trenovano na (runners+obdobi), nastaveni treningovych dat, počet epoch, hyperparametry, config atribu atp.) - mozna persistovat v db
|
# udelat nejaka model metadata (napr, trenovano na (runners+obdobi), nastaveni treningovych dat, počet epoch, hyperparametry, config atribu atp.) - mozna persistovat v db
|
||||||
# udelat nejake verzovani
|
# udelat nejake verzovani
|
||||||
# predelat do GUI a modulu
|
# predelat do GUI a modulu
|
||||||
# prepare data do importovane funkce, aby bylo mozno pouzit v predict casti ve strategii a nemuselo se porad udrzovat
|
# vyuzit VectorBT na dohledani optimalizovanych parametru napr. pro buy,sell atp. Vyuzit podobne API na pripravu dat jako model.
|
||||||
#s nastavenim modelu. To stejne i s nastavenim upravy features
|
# EVAL MODEL - umoznit vektorové přidání indikátoru do runneru (např. predikce v modulu, vectorBT, optimalizace atp) - vytvorit si na to API, podobne co mam, nacte runner, transformuje, sekvencuje, provede a pak zpetne transformuje a prida jako dalsi indikator. Lze pak použít i v gui.
|
||||||
|
# nove tlacitko "Display model prediction" na urovni archrunnera, které
|
||||||
|
# - má volbu model + jestli zobrazit jen predictionu jako novy indikator nebo i mse from ytarget (nutny i target)
|
||||||
|
# po spusteni pak:
|
||||||
|
# - zkonztoluje jestli runner ma indikatory,ktere odpovidaji features modelu (bar_ftrs, ind_ftrs, optional i target)
|
||||||
|
# - vektorově doplní predictionu (transformuje data, udela predictionu a Y transformuje zpet)
|
||||||
|
# - vysledek (jako nove indikatory) implantuje do runnerdetailu a zobrazi
|
||||||
|
# podivat se na dalsi parametry kerasu, napr. false positive atp.
|
||||||
|
# podivat se jeste na rozdil mezi vectorovou predikci a skalarni - proc je nekdy rozdil, odtrasovat - pripadne pogooglit
|
||||||
|
# odtrasovat, nekde je sum (zkusit si oboji v jednom skriptu a porovnat)
|
||||||
|
|
||||||
#TODO NAPADY Na modely
|
#TODO NAPADY Na modely
|
||||||
#binary identifikace trendu napr. pokud nasledujici 3 bary rostou (0-1)
|
#1.binary identifikace trendu napr. pokud nasledujici 3 bary rostou (0-1) nebo nasledujici bary roste momentum
|
||||||
#soustredit se na modely s vystupem 0-1 nebo -1 až 1
|
#2.soustredit se na modely s vystupem 0-1 nebo -1 až 1
|
||||||
|
#3.Vyzkouset jeden model, ktery by identifikoval trendy v obou smerech - -1 pro klesani a 1 pro stoupání.
|
||||||
|
#4.vyzkouset zda model vytvoreny z casti dne nebude funkcni na druhe casti (on the fly daily models)
|
||||||
|
#5.zkusit modely s a bez time (prizpusobit tomu kod v ModelML - zejmena jak na crossday sekvence) - mozna ze zecatku dat aspon pryc z indikatoru?
|
||||||
|
# Dat vsechny zbytecne features pryc, nechat tam jen ty podstatne - attention, tak cílím.
|
||||||
|
#6. zkusit vyuzit tickprice v nejaekm modelu, pripadne pak dalsi CBAR indikatory . vymslet tickbased features
|
||||||
|
#7. zkusit jako features nevyuzit standardni ceny, ale pouze indikatory reprezentujici chovani (fastslope,samebarslope,volume,tradencnt)
|
||||||
|
#8. relativni OHLC - model pouzivajici (jen) bary, ale misto hodnot ohlc udelat features reprezentujici vztahy(pomery) mezi temito velicinami. tzn. relativni ohlc
|
||||||
|
#9. jiny pristup by byl ucit model na konkretnich chunkach, ktere chci aby mi identifikoval. Např. určité úseky. Vymyslet. Buď nyni jako test intervaly, ale v budoucnu to treba jen nejak oznacit a poslat k nauceni. Pripadne pak udelat nejaky vycuc.
|
||||||
|
#10. mozna správným výběrem targetu, můžu taky naučit jen určité věci. Specializace. Stačí když se jednou dvakrát denně aktivuje.
|
||||||
|
# 11. udelat si go IN model, ktery pomuze strategii generovat vstup - staci jen aby mel trochu lepsi edge nez conditiony, o zbytek se postara logika strategie
|
||||||
|
# 12. model pro neagregované nebo jen filtroné či velmi lehce agregované trady?
|
||||||
|
|
||||||
|
#DULEZITE
|
||||||
|
# soustredit se v modelech na predikci nasledujici hodnoty, ideálně nějaký vektor ukazující směr (např. 0 - 1, kde nula nebude růst, 1 - bude růst strmě)
|
||||||
|
# pro predikcí nějakého většího trendu, zkusti více modelů na různých rozlišení, každý ukazuje
|
||||||
|
# hodnotu na svém rozlišení a jeho kombinace mi může určit vstup. Zkusit zda by nešel i jeden model.
|
||||||
|
# Každopádně se soustředit
|
||||||
|
# 1) na další hodnotu (tzn. vstupy musí být bezprostředně ovlivňující tuto (samebasrlope, atp.))
|
||||||
|
# 2) její výše ukazuje směr na tomto rozlišení
|
||||||
|
# 3) ideálně se učit z každého baru, tzn. cílová hodnota musí být známá u každého baru
|
||||||
|
# (binary ne, potřebuju linární vektor) - i když 1 a 0 target v závislosti na stoupání a klesání by mohla být ok,
|
||||||
|
# ale asi příliš restriktivní, spíš bych tam mohl dát jak moc. Tzn. +0.32, -0.04. Učilo by se to míru stoupání.
|
||||||
|
# Tu míru tam potřebuju zachovanou.
|
||||||
|
# pak si muzu rict, když je urcite pravdepodobnost, ze to bude stoupat (tzn. dalsi hodnota) na urovni 1,2,3 - tak jduvstup
|
||||||
|
# zkusit na nejnižší úrovni i předvídat CBARy, směr dalšího ticku. Vyzkoušet.
|
||||||
|
|
||||||
|
##TODO - doma
|
||||||
|
#bar_features a ind_features do dokumentace SL classic, stejne tak conditional indikator a mathop indikator
|
||||||
|
#TODO - co je třeba vyvinout
|
||||||
|
# GENERATOR test intervalu (vstup name, note, od,do,step)
|
||||||
|
# napsat API, doma pak simple GUI
|
||||||
|
# vyuziti ATR (jako hranice historickeho rozsahu) - atr-up, atr-down
|
||||||
|
# nakreslit v grafu atru = close+atr, atrd = close-atr
|
||||||
|
# pripadne si vypocet atr nejak customizovat, prip. ruzne multiplikatory pro high low, pripadne si to vypocist podle sebe
|
||||||
|
# vyuziti:
|
||||||
|
# pro prekroceni nejake lajny, napr. ema nebo yesterdayclose
|
||||||
|
# - k identifikaci ze se pohybuje v jejim rozsahu
|
||||||
|
# - proste je to buffer, ktery musi byt prekonan, aby byla urcita akce
|
||||||
|
# pro learning pro vypocet conditional parametru (1,0,-1) prekroceni napr. dailyopen, yesterdayclose, gapclose
|
||||||
|
# kde 1 prekroceno, 0 v rozsahu (atr), -1 prekroceno dolu - to pomuze uceni
|
||||||
|
# vlastni supertrend strateige
|
||||||
|
# zaroven moznost vyuzit klouzave či parametrizovane atr, které se na základě
|
||||||
|
# určitých parametrů bude samo upravovat a cíleně vybočovat z KONTRA frekvencí, např. randomizovaný multiplier nebo nejak jinak ovlivneny minulým
|
||||||
|
# v indikatorech vsude kde je odkaz ma source jako hodnotu tak defaultne mit moznost uvest lookback, napr. bude treba porovnavat nejak cenu vs predposledni hodnotu ATRka (nechat az vyvstane pozadavek)
|
||||||
|
# zacit doma na ATRku si postavit supertrend, viz pinescript na ploše
|
||||||
|
|
||||||
|
|
||||||
# Sample data (replace this with your actual OHLCV data)
|
#TODO - obecne vylepsovaky
|
||||||
bars = {
|
# 1. v GUI graf container do n-TABů, mozna i draggable order, zaviratelne na Xko (innerContainer)
|
||||||
'time': [1, 2, 3, 4, 5,6,7,8,9,10,11,12,13,14,15],
|
# 2. mit mozna specialni mod na pripravu dat (agreg+indikator, tzn. vse jen bez vstupů) - můžu pak zapracovat víc vectorové doplňování dat
|
||||||
'high': [10, 11, 12, 13, 14,10, 11, 12, 13, 14,10, 11, 12, 13, 14],
|
# TOTO:: mozna by postacil vypnout backtester (tzn. no trades) - a projet jen indikatory. mozna by slo i vectorove optimalizovat.
|
||||||
'low': [8, 9, 7, 6, 8,8, 9, 7, 6, 8,8, 9, 7, 6, 8],
|
# indikatory by se mohli predsunout pred next a next by se vubec nemusel volat (jen nekompatibilita s predch.strategiemi)
|
||||||
'volume': [1000, 1200, 900, 1100, 1300,1000, 1200, 900, 1100, 1300,1000, 1200, 900, 1100, 1300],
|
# 3. kombinace fastslope na fibonacci delkach (1,2,3,5..) jako dobry vstup pro ML
|
||||||
'close': [9, 10, 11, 12, 13,9, 10, 11, 12, 13,9, 10, 11, 12, 13],
|
# 4. podivat se na attention based LSTM zda je v kerasu implementace
|
||||||
'open': [9, 10, 8, 8, 8,9, 10, 8, 8, 8,9, 10, 8, 8, 8],
|
# do grafu přidat togglovatelné hranice barů určitých rozlišení - což mi jen udělá čáry Xs od sebe (dobré pro navrhování)
|
||||||
'resolution': [1, 1, 1, 1, 1,1, 1, 1, 1, 1,1, 1, 1, 1, 1]
|
# 5. vymyslet optimalizovane vyuziti modelu na produkci (nejak mit zkompilovane, aby to bylo raketově pro skalár) - nyní to backtest zpomalí 4x
|
||||||
}
|
# 6. CONVNETS for time series forecasting - small 1D convnets can offer a fast alternative to RNNs for simple tasks such as text classification and timeseries forecasting.
|
||||||
|
# zkusit small conv1D pro identifikaci víření před trendem, např. jen 6 barů - identifikovat dobře target, musí jít o tutovku na targetu
|
||||||
|
# pro covnet zkusit cbar price, volume a time. Třeba to zachytí víření (ripples)
|
||||||
|
# Další oblasti k predikci jsou ripples, vlnky - předzvěst nějakého mocnějšího pohybu. A je pravda, že předtím se mohou objevit nějaké indicie. Ty zkus zachytit.
|
||||||
|
# Do runner_headers pridat bt_from, bt_to - pro razeni order_by, aby se runnery vzdy vraceli vzestupne dle data (pro machine l)
|
||||||
|
|
||||||
indicators = {
|
#TODO
|
||||||
'time': [1, 2, 3, 4, 5,6,7,8,9,10,11,12,13,14,15],
|
# vyvoj modelů workflow s LSTMtrain.py
|
||||||
'fastslope': [90, 95, 100, 110, 115,90, 95, 100, 110, 115,90, 95, 100, 110, 115],
|
# 1) POC - pouze zde ve skriptu, nad 1-2 runnery, okamžité zobrazení v plotu,
|
||||||
'fsdelta': [90, 95, 100, 110, 115,90, 95, 100, 110, 115,90, 95, 100, 110, 115],
|
# optimalizace zakl. features a hyperparams. Zobrazit i u binary nejak cenu.
|
||||||
'fastslope2': [90, 95, 100, 110, 115,90, 95, 100, 110, 115,90, 95, 100, 110, 115],
|
# 2) REALITY CHECK - trening modelu na batchi test intervalu, overeni ve strategii v BT, zobrazeni predikce v RT chartu
|
||||||
'ema': [1000, 1200, 900, 1100, 1300,1000, 1200, 900, 1100, 1300,1000, 1200, 900, 1100, 1300]
|
# 3) FINAL TRAINING
|
||||||
}
|
# testovani predikce
|
||||||
|
|
||||||
|
|
||||||
# Zakladni nastaveni
|
#TODO tady
|
||||||
testlist_id = ""
|
# train model
|
||||||
runner_ids = ["838e918e-9be0-4251-a968-c13c83f3f173","c11c5cae-05f8-4b0a-aa4d-525ddac81684"]
|
# - train data- batch nebo runners
|
||||||
features = ["time","high","low","volume","open","close", "trades", "vwap","samebarslope", "fastslope","fsdelta", "fastslope2", "fsdelta2"]
|
# - test data - batch or runners (s cim porovnavat/validovat)
|
||||||
#TODO toto je linearni prediction mod, dodelat podporu BINARY
|
# - vyber architektury
|
||||||
|
# - soucast skriptu muze byt i porovnavacka pripadne nejaky search optimalnich parametru
|
||||||
|
|
||||||
|
#lstmtrain - podporit jednotlive kroky vyse
|
||||||
|
#modelML - udelat lepsi PODMINKY
|
||||||
|
#frontend? ma cenu? asi ano - GUI na model - new - train/retrain-change
|
||||||
|
# (vymyslet jak v gui chytře vybírat arch modelu a hyperparams, loss, optim - treba nejaka templata?)
|
||||||
|
# mozna ciselnik architektur s editačním polem pro kód -jen pár řádků(.add, .compile) přidat v editoru
|
||||||
|
# vymyslet jak to udělat pythonově
|
||||||
|
#testlist generator api
|
||||||
|
|
||||||
|
# endregion
|
||||||
|
|
||||||
|
#if null,the validation is made on 10% of train data
|
||||||
|
#runnery pro testovani
|
||||||
|
validation_runners = ["a38fc269-8df3-4374-9506-f0280d798854"]
|
||||||
|
|
||||||
#u binary bude target bud hotovy indikator a nebo jej vytvorit on the fly
|
#u binary bude target bud hotovy indikator a nebo jej vytvorit on the fly
|
||||||
|
cfg = ModelML(name="model1",
|
||||||
|
version = "0.1",
|
||||||
|
note = None,
|
||||||
|
pred_output=PredOutput.LINEAR,
|
||||||
|
input_sequences = 10,
|
||||||
|
use_bars = True,
|
||||||
|
bar_features = ["volume","trades"],
|
||||||
|
ind_features = ["slope20", "ema20","emaFast","samebarslope","fastslope","fastslope4"],
|
||||||
|
target='target', #referencni hodnota pro target - napr pro graf
|
||||||
|
target_reference='vwap',
|
||||||
|
train_target_steps=3,
|
||||||
|
train_target_transformation=TargetTRFM.KEEPVAL,
|
||||||
|
train_runner_ids = ["08b7f96e-79bc-4849-9142-19d5b28775a8"],
|
||||||
|
train_batch_id = None,
|
||||||
|
train_epochs = 10,
|
||||||
|
train_remove_cross_sequences = True,
|
||||||
|
)
|
||||||
|
|
||||||
#model muze byt take bez barů, tzn. jen indikatory
|
#TODO toto cele dat do TRAIN metody - vcetne pripadneho loopu a podpory API
|
||||||
use_bars = True
|
|
||||||
target = 'fastslope2'
|
|
||||||
#predict how many bars in the future
|
|
||||||
target_steps = 5
|
|
||||||
name = "model1"
|
|
||||||
seq = 10
|
|
||||||
epochs = 200
|
|
||||||
|
|
||||||
|
test_size = None
|
||||||
|
|
||||||
#crossday identifier je time (hodnota resolution je pouzita ne odstraneni sekvenci skrz dny)
|
#kdyz neplnime vstup, automaticky se loaduje training data z nastaveni classy
|
||||||
#predpoklad pouziti je crossday_sequence je time ve features
|
source_data, target_data, rows_in_day = cfg.load_data()
|
||||||
resolution = 1
|
|
||||||
crossday_sequence = False
|
|
||||||
#zda se model uci i crosseday (skrz runner/day data). Pokud ne, pak se crossday sekvence odstrani
|
|
||||||
#realizovano pomoci pomocneho identifikatoru (runner)
|
|
||||||
|
|
||||||
#zajistime poradi
|
if len(target_data) == 0:
|
||||||
features.sort()
|
raise Exception("target is empty - required for TRAINING - check target column name")
|
||||||
#cas na prvnim miste
|
|
||||||
if "time" in features:
|
|
||||||
features.remove("time")
|
|
||||||
features.insert(0, "time")
|
|
||||||
|
|
||||||
def merge_dicts(dict_list):
|
np.set_printoptions(threshold=10,edgeitems=5)
|
||||||
# Initialize an empty merged dictionary
|
#print("source_data", source_data)
|
||||||
merged_dict = {}
|
#print("target_data", target_data)
|
||||||
|
print("rows_in_day", rows_in_day)
|
||||||
|
source_data = cfg.scalerX.fit_transform(source_data)
|
||||||
|
|
||||||
# Iterate through the dictionaries in the list
|
#TODO mozna vyhodit to UNTR
|
||||||
for i,d in enumerate(dict_list):
|
#TODO asi vyhodit i target reference a vymyslet jinak
|
||||||
for key, value in d.items():
|
|
||||||
if key in merged_dict:
|
|
||||||
merged_dict[key] += value
|
|
||||||
else:
|
|
||||||
merged_dict[key] = value
|
|
||||||
#vlozime element s idenitfikaci runnera
|
|
||||||
|
|
||||||
return merged_dict
|
#vytvořeni sekvenci po vstupních sadách (např. 10 barů) - výstup 3D např. #X_train (6205, 10, 14)
|
||||||
|
#doplneni transformace target data
|
||||||
|
X_train, y_train, y_train_ref = cfg.create_sequences(combined_data=source_data,
|
||||||
|
target_data=target_data,
|
||||||
|
remove_cross_sequences=cfg.train_remove_cross_sequences,
|
||||||
|
rows_in_day=rows_in_day)
|
||||||
|
|
||||||
# # Initialize the merged dictionary with the first dictionary in the list
|
#zobrazime si transformovany target a jeho referncni sloupec
|
||||||
# merged_dict = dict_list[0].copy()
|
#ZHOMOGENIZOVAT OSY
|
||||||
# merged_dict["index"] = []
|
plt.plot(y_train, label='Transf target')
|
||||||
|
plt.plot(y_train_ref, label='Ref target')
|
||||||
|
plt.plot()
|
||||||
|
plt.legend()
|
||||||
|
plt.show()
|
||||||
|
|
||||||
# # Iterate through the remaining dictionaries and concatenate their lists
|
print("After sequencing")
|
||||||
# for i, d in enumerate(dict_list[1:]):
|
print("source:X_train", np.shape(X_train))
|
||||||
# merged_dict["index"] =
|
print("target:y_train", np.shape(y_train))
|
||||||
# for key, value in d.items():
|
print("target:", y_train)
|
||||||
# if key in merged_dict:
|
y_train = y_train.reshape(-1, 1)
|
||||||
# merged_dict[key] += value
|
|
||||||
# else:
|
|
||||||
# merged_dict[key] = value
|
|
||||||
|
|
||||||
# return merged_dict
|
|
||||||
|
|
||||||
def load_runner(runner_id):
|
|
||||||
res, sada = get_archived_runner_details_byID(runner_id)
|
|
||||||
if res == 0:
|
|
||||||
print("ok")
|
|
||||||
else:
|
|
||||||
print("error",res,sada)
|
|
||||||
|
|
||||||
bars = sada["bars"]
|
|
||||||
indicators = sada["indicators"][0]
|
|
||||||
return bars, indicators
|
|
||||||
|
|
||||||
def prepare_data(bars, indicators, features, target) -> tuple[np.array, np.array]:
|
|
||||||
#create SOURCE DATA with features
|
|
||||||
# bars and indicators dictionary and features as input
|
|
||||||
indicator_data = np.column_stack([indicators[feature] for feature in features if feature in indicators])
|
|
||||||
if len(bars)>0:
|
|
||||||
bar_data = np.column_stack([bars[feature] for feature in features if feature in bars])
|
|
||||||
combined_day_data = np.column_stack([bar_data,indicator_data])
|
|
||||||
else:
|
|
||||||
combined_day_data = indicator_data
|
|
||||||
|
|
||||||
#create TARGET DATA
|
|
||||||
try:
|
|
||||||
target_base = bars[target]
|
|
||||||
except KeyError:
|
|
||||||
target_base = indicators[target]
|
|
||||||
target_day_data = np.column_stack([target_base])
|
|
||||||
return combined_day_data, target_day_data
|
|
||||||
|
|
||||||
def load_runners_as_list(runner_ids: list, use_bars: bool):
|
|
||||||
"""Loads all runners data (bars, indicators) for runner_ids into list of dicts-
|
|
||||||
|
|
||||||
Args:
|
|
||||||
runner_ids: list of runner_ids.
|
|
||||||
use_bars: Whether to use also bars or just indicators
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
tuple (barslist, indicatorslist) - lists with dictionaries for each runner
|
|
||||||
"""
|
|
||||||
barslist = []
|
|
||||||
indicatorslist = []
|
|
||||||
for runner_id in runner_ids:
|
|
||||||
bars, indicators = load_runner(runner_id)
|
|
||||||
if use_bars:
|
|
||||||
barslist.append(bars)
|
|
||||||
indicatorslist.append(indicators)
|
|
||||||
|
|
||||||
return barslist, indicatorslist
|
|
||||||
|
|
||||||
def create_sequences(combined_data, target_data, seq, target_steps, crossday_sequence = True):
|
|
||||||
"""Creates sequences of given length seq and target N steps in the future.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
combined_data: A list of combined data.
|
|
||||||
target_data: A list of target data.
|
|
||||||
seq: The sequence length.
|
|
||||||
target_steps: The number of steps in the future to target.
|
|
||||||
crossday_sequence: Zda vytvaret sekvenci i skrz dny (runnery)
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
A list of X sequences and a list of y sequences.
|
|
||||||
"""
|
|
||||||
X_train = []
|
|
||||||
y_train = []
|
|
||||||
last_delta = None
|
|
||||||
for i in range(len(combined_data) - seq - target_steps):
|
|
||||||
if last_delta is None:
|
|
||||||
last_delta = 2*(combined_data[i + seq + target_steps, 0] - combined_data[i, 0])
|
|
||||||
|
|
||||||
curr_delta = combined_data[i + seq + target_steps, 0] - combined_data[i, 0]
|
|
||||||
#pokud je cas konce sequence vyrazne vetsi (2x) nez predchozi
|
|
||||||
#print(f"standardní zacatek {combined_data[i, 0]} konec {combined_data[i + seq + target_steps, 0]} delta: {curr_delta}")
|
|
||||||
if crossday_sequence is False and curr_delta > last_delta:
|
|
||||||
print(f"sekvence vyrazena. Zacatek {combined_data[i, 0]} konec {combined_data[i + seq + target_steps, 0]}")
|
|
||||||
continue
|
|
||||||
X_train.append(combined_data[i:i + seq])
|
|
||||||
y_train.append(target_data[i + seq + target_steps])
|
|
||||||
last_delta = 2*(combined_data[i + seq + target_steps, 0] - combined_data[i, 0])
|
|
||||||
return np.array(X_train), np.array(y_train)
|
|
||||||
|
|
||||||
barslist, indicatorslist = load_runners_as_list(runner_ids, use_bars)
|
|
||||||
|
|
||||||
#zmergujeme vsechny data dohromady
|
|
||||||
bars = merge_dicts(barslist)
|
|
||||||
indicators = merge_dicts(indicatorslist)
|
|
||||||
print(f"{len(indicators)}")
|
|
||||||
print(f"{len(bars)}")
|
|
||||||
source_data, target_data = prepare_data(bars, indicators, features, target)
|
|
||||||
|
|
||||||
# Set the printing threshold to print only the first and last 10 rows of the array
|
|
||||||
np.set_printoptions(threshold=10)
|
|
||||||
print("source_data", source_data, "shape", np.shape(source_data))
|
|
||||||
|
|
||||||
# Standardize the data
|
|
||||||
scalerX = StandardScaler()
|
|
||||||
scalerY = StandardScaler()
|
|
||||||
#FIT SCALER také fixuje počet FEATURES !!
|
|
||||||
source_data = scalerX.fit_transform(source_data)
|
|
||||||
target_data = scalerY.fit_transform(target_data)
|
|
||||||
|
|
||||||
#print("source_data shape",np.shape(source_data))
|
|
||||||
|
|
||||||
# Create a sequence of seq elements and define target prediction horizona
|
|
||||||
X_train, y_train = create_sequences(source_data, target_data, seq=seq, target_steps=target_steps, crossday_sequence=crossday_sequence)
|
|
||||||
|
|
||||||
#X_train (6205, 10, 14)
|
|
||||||
print("X_train", np.shape(X_train))
|
|
||||||
|
|
||||||
X_complete = np.array(X_train.copy())
|
X_complete = np.array(X_train.copy())
|
||||||
Y_complete = np.array(y_train.copy())
|
Y_complete = np.array(y_train.copy())
|
||||||
X_train = np.array(X_train)
|
X_train = np.array(X_train)
|
||||||
y_train = np.array(y_train)
|
y_train = np.array(y_train)
|
||||||
|
|
||||||
# Split the data into training and test sets
|
#target scaluji az po transformaci v create sequence -narozdil od X je stejny shape
|
||||||
X_train, X_test, y_train, y_test = train_test_split(X_train, y_train, test_size=0.20, shuffle=False) #random_state=42)
|
y_train = cfg.scalerY.fit_transform(y_train)
|
||||||
|
|
||||||
|
|
||||||
|
if len(validation_runners) == 0:
|
||||||
|
test_size = 0.10
|
||||||
|
# Split the data into training and test sets - kazdy vstupni pole rozdeli na dve
|
||||||
|
#nechame si takhle rozdelit i referencni sloupec
|
||||||
|
X_train, X_test, y_train, y_test, y_train_ref, y_test_ref = train_test_split(X_train, y_train, y_train_ref, test_size=test_size, shuffle=False) #random_state=42)
|
||||||
|
|
||||||
|
print("Splittig the data")
|
||||||
|
|
||||||
|
print("X_train", np.shape(X_train))
|
||||||
|
print("X_test", np.shape(X_test))
|
||||||
|
print("y_train", np.shape(y_train))
|
||||||
|
print("y_test", np.shape(y_test))
|
||||||
|
print("y_test_ref", np.shape(y_test_ref))
|
||||||
|
print("y_train_ref", np.shape(y_train_ref))
|
||||||
|
|
||||||
#print(np.shape(X_train))
|
#print(np.shape(X_train))
|
||||||
# Define the input shape of the LSTM layer dynamically based on the reshaped X_train value
|
# Define the input shape of the LSTM layer dynamically based on the reshaped X_train value
|
||||||
input_shape = (X_train.shape[1], X_train.shape[2])
|
input_shape = (X_train.shape[1], X_train.shape[2])
|
||||||
|
|
||||||
# Build the LSTM model
|
# Build the LSTM model
|
||||||
model = Sequential()
|
#cfg.model = Sequential()
|
||||||
model.add(LSTM(128, input_shape=input_shape))
|
cfg.model.add(LSTM(128, input_shape=input_shape))
|
||||||
model.add(Dense(1))
|
cfg.model.add(Dense(1, activation="relu"))
|
||||||
|
#activation: Gelu, relu, elu, sigmoid...
|
||||||
# Compile the model
|
# Compile the model
|
||||||
model.compile(loss='mse', optimizer='adam')
|
cfg.model.compile(loss='mse', optimizer='adam')
|
||||||
|
#loss: mse, binary_crossentropy
|
||||||
|
|
||||||
# Train the model
|
# Train the model
|
||||||
model.fit(X_train, y_train, epochs=epochs)
|
cfg.model.fit(X_train, y_train, epochs=cfg.train_epochs)
|
||||||
|
|
||||||
#save the model
|
#save the model
|
||||||
#model.save(DATA_DIR+'/my_model.keras')
|
cfg.save()
|
||||||
#model = load_model(DATA_DIR+'/my_model.keras')
|
|
||||||
dump(scalerX, DATA_DIR+'/'+name+'scalerX.pkl')
|
|
||||||
dump(scalerY, DATA_DIR+'/'+name+'scalerY.pkl')
|
|
||||||
dump(model, DATA_DIR+'/'+name+'.pkl')
|
|
||||||
|
|
||||||
model = load(DATA_DIR+'/'+ name +'.pkl')
|
#TBD db layer
|
||||||
scalerX: StandardScaler = load(DATA_DIR+'/'+ name +'scalerX.pkl')
|
cfg: ModelML = mu.load_model(cfg.name, cfg.version)
|
||||||
scalerY: StandardScaler = load(DATA_DIR+'/'+ name +'scalerY.pkl')
|
|
||||||
|
|
||||||
#LIVE PREDICTION - IMAGINE THIS HAPPENS LIVE
|
# region Live predict
|
||||||
# Get the live data
|
#EVALUATE SIM LIVE - PREDICT SCALAR - based on last X items
|
||||||
# Prepare the data for bars and indicators
|
barslist, indicatorslist = cfg.load_runners_as_list(runner_id_list=["67b51211-d353-44d7-a58a-5ae298436da7"])
|
||||||
|
#zmergujeme vsechny data dohromady
|
||||||
|
bars = mu.merge_dicts(barslist)
|
||||||
|
indicators = mu.merge_dicts(indicatorslist)
|
||||||
|
cfg.validate_available_features(bars, indicators)
|
||||||
|
#VSTUPEM JE standardni pole v strategii
|
||||||
|
value = cfg.predict(bars, indicators)
|
||||||
|
print("prediction for LIVE SIM:", value)
|
||||||
|
# endregion
|
||||||
|
|
||||||
#asume ohlc_features and indicator_features remain the same
|
#EVALUATE TEST DATA - VECTOR BASED
|
||||||
|
#pokud mame eval runners pouzijeme ty, jinak bereme cast z testovacich dat
|
||||||
|
if len(validation_runners) > 0:
|
||||||
|
source_data, target_data, rows_in_day = cfg.load_data(runners_ids=validation_runners)
|
||||||
|
source_data = cfg.scalerX.fit_transform(source_data)
|
||||||
|
X_test, y_test, y_test_ref = cfg.create_sequences(combined_data=source_data, target_data=target_data,remove_cross_sequences=True, rows_in_day=rows_in_day)
|
||||||
|
|
||||||
|
#prepnout ZDE pokud testovat cely bundle - jinak testujeme jen neznama
|
||||||
|
#X_test = X_complete
|
||||||
|
#y_test = Y_complete
|
||||||
|
|
||||||
#get last 5 items of respective indicators
|
X_test = cfg.model.predict(X_test)
|
||||||
|
X_test = cfg.scalerY.inverse_transform(X_test)
|
||||||
|
|
||||||
#mazeme runner indikator pokud tu je
|
#target testovacim dat proc tu je reshape? y_test.reshape(-1, 1)
|
||||||
if "runner" in indicators:
|
y_test = cfg.scalerY.inverse_transform(y_test)
|
||||||
del indicators["runner"]
|
#celkovy mean? nebo spis vector pro graf?
|
||||||
print("runner key deleted from indicators")
|
mse = mean_squared_error(y_test, X_test)
|
||||||
|
|
||||||
if "runner" in features:
|
|
||||||
features.remove("runner")
|
|
||||||
print("runner removed from features")
|
|
||||||
|
|
||||||
lastNbars = slice_dict_lists(bars, seq)
|
|
||||||
lastNindicators = slice_dict_lists(indicators, seq)
|
|
||||||
print("last5bars", lastNbars)
|
|
||||||
print("last5indicators",lastNindicators)
|
|
||||||
|
|
||||||
indicator_data = np.column_stack([lastNindicators[feature] for feature in features if feature in lastNindicators])
|
|
||||||
if use_bars:
|
|
||||||
bar_data = np.column_stack([lastNbars[feature] for feature in features if feature in lastNbars])
|
|
||||||
combined_live_data = np.column_stack([bar_data, indicator_data])
|
|
||||||
else:
|
|
||||||
combined_live_data = indicator_data
|
|
||||||
print("combined_live_data",combined_live_data)
|
|
||||||
combined_live_data = scalerX.transform(combined_live_data)
|
|
||||||
#scaler = StandardScaler()
|
|
||||||
|
|
||||||
combined_live_data = np.array(combined_live_data)
|
|
||||||
|
|
||||||
#converts to 3D array
|
|
||||||
# 1 number of samples in the array.
|
|
||||||
# 2 represents the sequence length.
|
|
||||||
# 3 represents the number of features in the data.
|
|
||||||
combined_live_data = combined_live_data.reshape((1, seq, combined_live_data.shape[1]))
|
|
||||||
|
|
||||||
|
|
||||||
# Make a prediction
|
|
||||||
prediction = model(combined_live_data, training=False)
|
|
||||||
#prediction = prediction.reshape((1, 1))
|
|
||||||
# Convert the prediction back to the original scale
|
|
||||||
prediction = scalerY.inverse_transform(prediction)
|
|
||||||
|
|
||||||
print("prediction for last value", float(prediction))
|
|
||||||
|
|
||||||
#TEST PREDICATIONS
|
|
||||||
# Evaluate the model on the test set
|
|
||||||
#pozor testovaci sadu na produkc scalovat samostatne
|
|
||||||
#X_test = scalerX.transform(X_test)
|
|
||||||
#predikce nad testovacimi daty
|
|
||||||
X_complete = model.predict(X_complete)
|
|
||||||
X_complete = scalerY.inverse_transform(X_complete)
|
|
||||||
|
|
||||||
#target testovacim dat
|
|
||||||
Y_complete = scalerY.inverse_transform(Y_complete)
|
|
||||||
mse = mean_squared_error(Y_complete, X_complete)
|
|
||||||
print('Test MSE:', mse)
|
print('Test MSE:', mse)
|
||||||
|
|
||||||
# Plot the predicted vs. actual close prices
|
# Plot the predicted vs. actual
|
||||||
plt.plot(Y_complete, label='Actual')
|
plt.plot(y_test, label='Actual')
|
||||||
plt.plot(X_complete, label='Predicted')
|
plt.plot(X_test, label='Predicted')
|
||||||
|
#TODO zde nejak vymyslet jinou pricelinu - jako lightweight chart
|
||||||
|
plt.plot(y_test_ref, label='reference column - price')
|
||||||
|
plt.plot()
|
||||||
plt.legend()
|
plt.legend()
|
||||||
plt.show()
|
plt.show()
|
||||||
|
|
||||||
# To make a prediction, we can simply feed the model a sequence of 5 elements and it will predict the next element. For example, to predict the close price for the 6th time period, we would feed the model the following sequence:
|
|
||||||
|
|
||||||
# sequence = combined_data[0:5]
|
|
||||||
# prediction = model.predict(sequence)
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
from uuid import UUID, uuid4
|
from uuid import UUID
|
||||||
from alpaca.trading.enums import OrderSide, OrderStatus, TradeEvent, OrderClass, OrderType, TimeInForce
|
from alpaca.trading.enums import OrderSide, OrderStatus, TradeEvent,OrderType
|
||||||
#from utils import AttributeDict
|
#from utils import AttributeDict
|
||||||
from rich import print
|
from rich import print
|
||||||
from typing import Any, Optional, List, Union
|
from typing import Any, Optional, List, Union
|
||||||
@ -24,6 +24,7 @@ from alpaca.data.enums import Exchange
|
|||||||
# return user.id
|
# return user.id
|
||||||
# raise HTTPException(status_code=404, detail=f"Could not find user with id: {id}")
|
# raise HTTPException(status_code=404, detail=f"Could not find user with id: {id}")
|
||||||
|
|
||||||
|
|
||||||
# Define a Pydantic model for input data
|
# Define a Pydantic model for input data
|
||||||
class ConfigItem(BaseModel):
|
class ConfigItem(BaseModel):
|
||||||
id: Optional[int] = None
|
id: Optional[int] = None
|
||||||
@ -78,7 +79,10 @@ class RunRequest(BaseModel):
|
|||||||
ilog_save: bool = False
|
ilog_save: bool = False
|
||||||
bt_from: datetime = None
|
bt_from: datetime = None
|
||||||
bt_to: datetime = None
|
bt_to: datetime = None
|
||||||
|
#id testovaciho intervalu TODO prejmenovat
|
||||||
test_batch_id: Optional[str] = None
|
test_batch_id: Optional[str] = None
|
||||||
|
#GENERATED ID v ramci runu, vaze vsechny runnery v batchovem behu
|
||||||
|
batch_id: Optional[str] = None
|
||||||
cash: int = 100000
|
cash: int = 100000
|
||||||
|
|
||||||
|
|
||||||
@ -103,6 +107,7 @@ class RunnerView(BaseModel):
|
|||||||
class Runner(BaseModel):
|
class Runner(BaseModel):
|
||||||
id: UUID
|
id: UUID
|
||||||
strat_id: UUID
|
strat_id: UUID
|
||||||
|
batch_id: Optional[str] = None
|
||||||
run_started: Optional[datetime] = None
|
run_started: Optional[datetime] = None
|
||||||
run_mode: Mode
|
run_mode: Mode
|
||||||
run_account: Account
|
run_account: Account
|
||||||
@ -190,6 +195,7 @@ class RunArchive(BaseModel):
|
|||||||
id: UUID
|
id: UUID
|
||||||
#id of running strategy (stratin/runner)
|
#id of running strategy (stratin/runner)
|
||||||
strat_id: UUID
|
strat_id: UUID
|
||||||
|
batch_id: Optional[str] = None
|
||||||
symbol: str
|
symbol: str
|
||||||
name: str
|
name: str
|
||||||
note: Optional[str] = None
|
note: Optional[str] = None
|
||||||
|
|||||||
@ -4,6 +4,8 @@ from appdirs import user_data_dir
|
|||||||
|
|
||||||
#TODO vybrane dat do config db a managovat pres GUI
|
#TODO vybrane dat do config db a managovat pres GUI
|
||||||
|
|
||||||
|
OFFLINE_MODE = False
|
||||||
|
|
||||||
#ilog lvls = 0,1 - 0 debug, 1 info
|
#ilog lvls = 0,1 - 0 debug, 1 info
|
||||||
ILOG_SAVE_LEVEL_FROM = 1
|
ILOG_SAVE_LEVEL_FROM = 1
|
||||||
|
|
||||||
@ -118,3 +120,5 @@ class KW:
|
|||||||
reverse: str = "reverse"
|
reverse: str = "reverse"
|
||||||
#exitaddsize: str = "exitaddsize"
|
#exitaddsize: str = "exitaddsize"
|
||||||
slreverseonly: str = "slreverseonly"
|
slreverseonly: str = "slreverseonly"
|
||||||
|
#klicove slovo pro Indikatory
|
||||||
|
change_val: str = "change_val"
|
||||||
|
|||||||
@ -340,6 +340,7 @@ def get_testlist_byID(record_id: str):
|
|||||||
|
|
||||||
#volano pro batchove spousteni (BT,)
|
#volano pro batchove spousteni (BT,)
|
||||||
def run_batch_stratin(id: UUID, runReq: RunRequest):
|
def run_batch_stratin(id: UUID, runReq: RunRequest):
|
||||||
|
#pozor toto je test interval id (batch id se pak generuje pro kazdy davkovy run tohoto intervalu)
|
||||||
if runReq.test_batch_id is None:
|
if runReq.test_batch_id is None:
|
||||||
return (-1, "batch_id required for batch run")
|
return (-1, "batch_id required for batch run")
|
||||||
|
|
||||||
@ -376,6 +377,7 @@ def batch_run_manager(id: UUID, runReq: RunRequest, testlist: TestList):
|
|||||||
#taky budu mit nejaky konfiguracni RUN MANAGER, tak by krome rizeniho denniho runu
|
#taky budu mit nejaky konfiguracni RUN MANAGER, tak by krome rizeniho denniho runu
|
||||||
#mohl podporovat i BATCH RUNy.
|
#mohl podporovat i BATCH RUNy.
|
||||||
batch_id = str(uuid4())[:8]
|
batch_id = str(uuid4())[:8]
|
||||||
|
runReq.batch_id = batch_id
|
||||||
print("generated batch_ID", batch_id)
|
print("generated batch_ID", batch_id)
|
||||||
|
|
||||||
print("test batch", testlist)
|
print("test batch", testlist)
|
||||||
@ -490,6 +492,7 @@ def run_stratin(id: UUID, runReq: RunRequest, synchronous: bool = False, inter_b
|
|||||||
#id runneru je nove id, stratin se dava dalsiho parametru
|
#id runneru je nove id, stratin se dava dalsiho parametru
|
||||||
runner = Runner(id = id,
|
runner = Runner(id = id,
|
||||||
strat_id = i.id,
|
strat_id = i.id,
|
||||||
|
batch_id = runReq.batch_id,
|
||||||
run_started = datetime.now(zoneNY),
|
run_started = datetime.now(zoneNY),
|
||||||
run_pause_ev = pe,
|
run_pause_ev = pe,
|
||||||
run_name = name,
|
run_name = name,
|
||||||
@ -647,6 +650,9 @@ def archive_runner(runner: Runner, strat: StrategyInstance, inter_batch_params:
|
|||||||
bp_from = None
|
bp_from = None
|
||||||
bp_to = None
|
bp_to = None
|
||||||
|
|
||||||
|
#get rid of attributes that are links to the models
|
||||||
|
strat.state.vars["loaded_models"] = {}
|
||||||
|
|
||||||
settings = dict(resolution=strat.state.timeframe,
|
settings = dict(resolution=strat.state.timeframe,
|
||||||
rectype=strat.state.rectype,
|
rectype=strat.state.rectype,
|
||||||
configs=dict(
|
configs=dict(
|
||||||
@ -671,6 +677,7 @@ def archive_runner(runner: Runner, strat: StrategyInstance, inter_batch_params:
|
|||||||
|
|
||||||
runArchive: RunArchive = RunArchive(id = runner.id,
|
runArchive: RunArchive = RunArchive(id = runner.id,
|
||||||
strat_id = runner.strat_id,
|
strat_id = runner.strat_id,
|
||||||
|
batch_id = runner.batch_id,
|
||||||
name=runner.run_name,
|
name=runner.run_name,
|
||||||
note=runner.run_note,
|
note=runner.run_note,
|
||||||
symbol=runner.run_symbol,
|
symbol=runner.run_symbol,
|
||||||
@ -787,12 +794,26 @@ def get_archived_runner_header_byID(id: UUID):
|
|||||||
else:
|
else:
|
||||||
return 0, res
|
return 0, res
|
||||||
|
|
||||||
|
#vrátí seznam runneru s danym batch_id
|
||||||
|
def get_archived_runnerslist_byBatchID(batch_id: str):
|
||||||
|
conn = pool.get_connection()
|
||||||
|
try:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute(f"SELECT runner_id FROM runner_header WHERE batch_id='{str(batch_id)}'")
|
||||||
|
runner_list = [row[0] for row in cursor.fetchall()]
|
||||||
|
finally:
|
||||||
|
pool.release_connection(conn)
|
||||||
|
return 0, runner_list
|
||||||
|
|
||||||
def insert_archive_header(archeader: RunArchive):
|
def insert_archive_header(archeader: RunArchive):
|
||||||
conn = pool.get_connection()
|
conn = pool.get_connection()
|
||||||
try:
|
try:
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
json_string = json.dumps(archeader, default=json_serial)
|
json_string = json.dumps(archeader, default=json_serial)
|
||||||
statement = f"INSERT INTO runner_header VALUES ('{str(archeader.id)}','{json_string}')"
|
if archeader.batch_id is not None:
|
||||||
|
statement = f"INSERT INTO runner_header (runner_id, batch_id, data) VALUES ('{str(archeader.id)}','{str(archeader.batch_id)}','{json_string}')"
|
||||||
|
else:
|
||||||
|
statement = f"INSERT INTO runner_header (runner_id, data) VALUES ('{str(archeader.id)}','{json_string}')"
|
||||||
res = c.execute(statement)
|
res = c.execute(statement)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
finally:
|
finally:
|
||||||
@ -913,6 +934,17 @@ def get_archived_runner_details_byID(id: UUID):
|
|||||||
else:
|
else:
|
||||||
return 0, res
|
return 0, res
|
||||||
|
|
||||||
|
def update_archive_detail(id: UUID, archdetail: RunArchiveDetail):
|
||||||
|
conn = pool.get_connection()
|
||||||
|
try:
|
||||||
|
c = conn.cursor()
|
||||||
|
json_string = json.dumps(archdetail, default=json_serial)
|
||||||
|
res = c.execute(f"UPDATE runner_detail SET data = '{json_string}' WHERE runner_id='{str(id)}'")
|
||||||
|
conn.commit()
|
||||||
|
finally:
|
||||||
|
pool.release_connection(conn)
|
||||||
|
return res.rowcount
|
||||||
|
|
||||||
def insert_archive_detail(archdetail: RunArchiveDetail):
|
def insert_archive_detail(archdetail: RunArchiveDetail):
|
||||||
conn = pool.get_connection()
|
conn = pool.get_connection()
|
||||||
try:
|
try:
|
||||||
|
|||||||
@ -1,5 +1,22 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from alpaca.trading.enums import OrderSide, OrderStatus, OrderType
|
from alpaca.trading.enums import OrderSide, OrderStatus, OrderType
|
||||||
|
|
||||||
|
class TargetTRFM(str, Enum):
|
||||||
|
#ponecha as is
|
||||||
|
KEEPVAL = "keepval"
|
||||||
|
#ponecha jen posune N-steps dopredu
|
||||||
|
KEEPVAL_MOVE = "keepval_move"
|
||||||
|
#posune o N-steps dopredu a hodnotu upravi na 1 nebo 0 podle toho jestli stoupa
|
||||||
|
#nejspis tohle bude delat v indikatorech pri priprave dat ve strategii a vyuzitvat KEEP a KEEP_STEPS
|
||||||
|
BINARY_TREND_UP = "binary_trend_up"
|
||||||
|
|
||||||
|
class Source(str, Enum):
|
||||||
|
RUNNERS = "runners"
|
||||||
|
SAMPLES = "sample"
|
||||||
|
|
||||||
|
class PredOutput(str, Enum):
|
||||||
|
LINEAR = "linear"
|
||||||
|
BINARY = "binary"
|
||||||
class Order:
|
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:
|
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.id = id
|
||||||
@ -42,12 +59,16 @@ class RecordType(str, Enum):
|
|||||||
|
|
||||||
class Mode(str, Enum):
|
class Mode(str, Enum):
|
||||||
"""
|
"""
|
||||||
LIVE or BT
|
LIVE - live on production
|
||||||
|
PAPER - on paper account
|
||||||
|
BT - full backtest
|
||||||
|
PREP - only prepare data (indicators and bars), no trades performed
|
||||||
"""
|
"""
|
||||||
|
|
||||||
PAPER = "paper"
|
PAPER = "paper"
|
||||||
LIVE = "live"
|
LIVE = "live"
|
||||||
BT = "backtest"
|
BT = "backtest"
|
||||||
|
PREP = "prep"
|
||||||
|
|
||||||
|
|
||||||
class StartBarAlign(str, Enum):
|
class StartBarAlign(str, Enum):
|
||||||
|
|||||||
@ -23,6 +23,13 @@ def natr(data_high, data_low, data_close, period: int = 5):
|
|||||||
natr = ti.natr(data_high, data_low, data_close, period=period)
|
natr = ti.natr(data_high, data_low, data_close, period=period)
|
||||||
return natr
|
return natr
|
||||||
|
|
||||||
|
def atr(data_high, data_low, data_close, period: int = 5):
|
||||||
|
data_high = convert_to_numpy(data_high)
|
||||||
|
data_low = convert_to_numpy(data_low)
|
||||||
|
data_close = convert_to_numpy(data_close)
|
||||||
|
atr = ti.atr(data_high, data_low, data_close, period=period)
|
||||||
|
return atr
|
||||||
|
|
||||||
def ema(data, period: int = 50, use_series=False):
|
def ema(data, period: int = 50, use_series=False):
|
||||||
if check_series(data):
|
if check_series(data):
|
||||||
use_series = True
|
use_series = True
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@ -2,14 +2,14 @@ from v2realbot.loader.aggregator import TradeAggregator, TradeAggregator2List, T
|
|||||||
from alpaca.trading.requests import GetCalendarRequest
|
from alpaca.trading.requests import GetCalendarRequest
|
||||||
from alpaca.trading.client import TradingClient
|
from alpaca.trading.client import TradingClient
|
||||||
from alpaca.data.live import StockDataStream
|
from alpaca.data.live import StockDataStream
|
||||||
from v2realbot.config import ACCOUNT1_PAPER_API_KEY, ACCOUNT1_PAPER_SECRET_KEY, DATA_DIR
|
from v2realbot.config import ACCOUNT1_PAPER_API_KEY, ACCOUNT1_PAPER_SECRET_KEY, DATA_DIR, OFFLINE_MODE
|
||||||
from alpaca.data.enums import DataFeed
|
from alpaca.data.enums import DataFeed
|
||||||
from alpaca.data.historical import StockHistoricalDataClient
|
from alpaca.data.historical import StockHistoricalDataClient
|
||||||
from alpaca.data.requests import StockLatestQuoteRequest, StockBarsRequest, StockTradesRequest
|
from alpaca.data.requests import StockLatestQuoteRequest, StockBarsRequest, StockTradesRequest
|
||||||
from threading import Thread, current_thread
|
from threading import Thread, current_thread
|
||||||
from v2realbot.utils.utils import parse_alpaca_timestamp, ltp, zoneNY, print
|
from v2realbot.utils.utils import parse_alpaca_timestamp, ltp, zoneNY, print
|
||||||
from v2realbot.utils.tlog import tlog
|
from v2realbot.utils.tlog import tlog
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta, date
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
import asyncio
|
import asyncio
|
||||||
from msgpack.ext import Timestamp
|
from msgpack.ext import Timestamp
|
||||||
@ -19,7 +19,7 @@ import pickle
|
|||||||
import os
|
import os
|
||||||
from rich import print
|
from rich import print
|
||||||
import queue
|
import queue
|
||||||
|
from alpaca.trading.models import Calendar
|
||||||
"""
|
"""
|
||||||
Trade offline data streamer, based on Alpaca historical data.
|
Trade offline data streamer, based on Alpaca historical data.
|
||||||
"""
|
"""
|
||||||
@ -98,10 +98,16 @@ class Trade_Offline_Streamer(Thread):
|
|||||||
#REFACTOR STARTS HERE
|
#REFACTOR STARTS HERE
|
||||||
#print(f"{self.time_from=} {self.time_to=}")
|
#print(f"{self.time_from=} {self.time_to=}")
|
||||||
|
|
||||||
calendar_request = GetCalendarRequest(start=self.time_from,end=self.time_to)
|
if OFFLINE_MODE:
|
||||||
cal_dates = self.clientTrading.get_calendar(calendar_request)
|
#just one day - same like time_from
|
||||||
#ic(cal_dates)
|
den = str(self.time_to.date())
|
||||||
#zatim podpora pouze main session
|
bt_day = Calendar(date=den,open="9:30",close="16:00")
|
||||||
|
cal_dates = [bt_day]
|
||||||
|
else:
|
||||||
|
calendar_request = GetCalendarRequest(start=self.time_from,end=self.time_to)
|
||||||
|
cal_dates = self.clientTrading.get_calendar(calendar_request)
|
||||||
|
#ic(cal_dates)
|
||||||
|
#zatim podpora pouze main session
|
||||||
|
|
||||||
#zatim podpora pouze 1 symbolu, predelat na froloop vsech symbolu ze symbpole
|
#zatim podpora pouze 1 symbolu, predelat na froloop vsech symbolu ze symbpole
|
||||||
#minimalni jednotka pro CACHE je 1 den - a to jen marketopen to marketclose (extended hours not supported yet)
|
#minimalni jednotka pro CACHE je 1 den - a to jen marketopen to marketclose (extended hours not supported yet)
|
||||||
|
|||||||
@ -1,13 +1,10 @@
|
|||||||
import os,sys
|
import os,sys
|
||||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
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, DATA_DIR
|
from v2realbot.config import WEB_API_KEY, DATA_DIR
|
||||||
from alpaca.data.timeframe import TimeFrame, TimeFrameUnit
|
from alpaca.data.timeframe import TimeFrame, TimeFrameUnit
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
#from icecream import install, ic
|
|
||||||
import os
|
import os
|
||||||
from rich import print
|
from rich import print
|
||||||
from threading import current_thread
|
|
||||||
from fastapi import FastAPI, Depends, HTTPException, status
|
from fastapi import FastAPI, Depends, HTTPException, status
|
||||||
from fastapi.security import APIKeyHeader
|
from fastapi.security import APIKeyHeader
|
||||||
import uvicorn
|
import uvicorn
|
||||||
@ -16,7 +13,7 @@ import v2realbot.controller.services as cs
|
|||||||
from v2realbot.utils.ilog import get_log_window
|
from v2realbot.utils.ilog import get_log_window
|
||||||
from v2realbot.common.model import StrategyInstance, RunnerView, RunRequest, Trade, RunArchive, RunArchiveDetail, Bar, RunArchiveChange, TestList, ConfigItem
|
from v2realbot.common.model import StrategyInstance, RunnerView, RunRequest, Trade, RunArchive, RunArchiveDetail, Bar, RunArchiveChange, TestList, ConfigItem
|
||||||
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Depends, HTTPException, status, WebSocketException, Cookie, Query
|
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Depends, HTTPException, status, WebSocketException, Cookie, Query
|
||||||
from fastapi.responses import HTMLResponse, FileResponse
|
from fastapi.responses import FileResponse
|
||||||
from fastapi.staticfiles import StaticFiles
|
from fastapi.staticfiles import StaticFiles
|
||||||
from fastapi.security import HTTPBasic, HTTPBasicCredentials
|
from fastapi.security import HTTPBasic, HTTPBasicCredentials
|
||||||
from typing import Annotated
|
from typing import Annotated
|
||||||
@ -286,20 +283,22 @@ def migrate():
|
|||||||
try:
|
try:
|
||||||
conn.row_factory = lambda c, r: json.loads(r[0])
|
conn.row_factory = lambda c, r: json.loads(r[0])
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
res = c.execute(f'CREATE TABLE "runner_header" ("runner_id" varchar(32) NOT NULL,"data" json NOT NULL, PRIMARY KEY("runner_id"))')
|
statement = f'ALTER TABLE "runner_header" ADD COLUMN "batch_id" TEXT'
|
||||||
|
res = c.execute(statement)
|
||||||
print(res)
|
print(res)
|
||||||
print("table created")
|
print("table created")
|
||||||
conn.commit()
|
conn.commit()
|
||||||
finally:
|
finally:
|
||||||
conn.row_factory = None
|
conn.row_factory = None
|
||||||
pool.release_connection(conn)
|
pool.release_connection(conn)
|
||||||
|
|
||||||
res, set =cs.migrate_archived_runners()
|
|
||||||
if res == 0:
|
|
||||||
open(lock_file, 'w').close()
|
open(lock_file, 'w').close()
|
||||||
return set
|
|
||||||
else:
|
# res, set =cs.migrate_archived_runners()
|
||||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"No data found")
|
# if res == 0:
|
||||||
|
# open(lock_file, 'w').close()
|
||||||
|
# return set
|
||||||
|
# else:
|
||||||
|
# raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"No data found")
|
||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|||||||
388
v2realbot/ml/ml.py
Normal file
388
v2realbot/ml/ml.py
Normal file
@ -0,0 +1,388 @@
|
|||||||
|
from sklearn.preprocessing import StandardScaler
|
||||||
|
from keras.models import Sequential
|
||||||
|
from v2realbot.enums.enums import PredOutput, Source, TargetTRFM
|
||||||
|
from v2realbot.config import DATA_DIR
|
||||||
|
from joblib import dump
|
||||||
|
import v2realbot.ml.mlutils as mu
|
||||||
|
from v2realbot.utils.utils import slice_dict_lists
|
||||||
|
import numpy as np
|
||||||
|
from copy import deepcopy
|
||||||
|
from v2realbot.controller.services import get_archived_runnerslist_byBatchID
|
||||||
|
#Basic classes for machine learning
|
||||||
|
#drzi model a jeho zakladni nastaveni
|
||||||
|
|
||||||
|
#Sample Data
|
||||||
|
sample_bars = {
|
||||||
|
'time': [1, 2, 3, 4, 5,6,7,8,9,10,11,12,13,14,15],
|
||||||
|
'high': [10, 11, 12, 13, 14,10, 11, 12, 13, 14,10, 11, 12, 13, 14],
|
||||||
|
'low': [8, 9, 7, 6, 8,8, 9, 7, 6, 8,8, 9, 7, 6, 8],
|
||||||
|
'volume': [1000, 1200, 900, 1100, 1300,1000, 1200, 900, 1100, 1300,1000, 1200, 900, 1100, 1300],
|
||||||
|
'close': [9, 10, 11, 12, 13,9, 10, 11, 12, 13,9, 10, 11, 12, 13],
|
||||||
|
'open': [9, 10, 8, 8, 8,9, 10, 8, 8, 8,9, 10, 8, 8, 8],
|
||||||
|
'resolution': [1, 1, 1, 1, 1,1, 1, 1, 1, 1,1, 1, 1, 1, 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
sample_indicators = {
|
||||||
|
'time': [1, 2, 3, 4, 5,6,7,8,9,10,11,12,13,14,15],
|
||||||
|
'fastslope': [90, 95, 100, 110, 115,90, 95, 100, 110, 115,90, 95, 100, 110, 115],
|
||||||
|
'fsdelta': [90, 95, 100, 110, 115,90, 95, 100, 110, 115,90, 95, 100, 110, 115],
|
||||||
|
'fastslope2': [90, 95, 100, 110, 115,90, 95, 100, 110, 115,90, 95, 100, 110, 115],
|
||||||
|
'ema': [1000, 1200, 900, 1100, 1300,1000, 1200, 900, 1100, 1300,1000, 1200, 900, 1100, 1300]
|
||||||
|
}
|
||||||
|
|
||||||
|
#Trida, která drzi instanci ML modelu a jeho konfigurace
|
||||||
|
#take se pouziva jako nastroj na pripravu dat pro train a predikci
|
||||||
|
#pozor samotna data trida neobsahuje, jen konfiguraci a pak samotny model
|
||||||
|
class ModelML:
|
||||||
|
def __init__(self, name: str,
|
||||||
|
pred_output: PredOutput,
|
||||||
|
bar_features: list,
|
||||||
|
ind_features: list,
|
||||||
|
input_sequences: int,
|
||||||
|
target: str,
|
||||||
|
target_reference: str,
|
||||||
|
train_target_steps: int, #train
|
||||||
|
train_target_transformation: TargetTRFM, #train
|
||||||
|
train_epochs: int, #train
|
||||||
|
train_runner_ids: list = None, #train
|
||||||
|
train_batch_id: str = None, #train
|
||||||
|
version: str = "1",
|
||||||
|
note : str = None,
|
||||||
|
use_bars: bool = True,
|
||||||
|
train_remove_cross_sequences: bool = False, #train
|
||||||
|
#standardne StandardScaler
|
||||||
|
scalerX: StandardScaler = StandardScaler(),
|
||||||
|
scalerY: StandardScaler = StandardScaler(),
|
||||||
|
model: Sequential = Sequential()) -> None:
|
||||||
|
|
||||||
|
self.name = name
|
||||||
|
self.version = version
|
||||||
|
self.note = note
|
||||||
|
self.pred_output: PredOutput = pred_output
|
||||||
|
#model muze byt take bez barů, tzn. jen indikatory
|
||||||
|
self.use_bars = use_bars
|
||||||
|
#zajistime poradi
|
||||||
|
bar_features.sort()
|
||||||
|
ind_features.sort()
|
||||||
|
self.bar_features = bar_features
|
||||||
|
self.ind_features = ind_features
|
||||||
|
if (train_runner_ids is None or len(train_runner_ids) == 0) and train_batch_id is None:
|
||||||
|
raise Exception("train_runner_ids nebo train_batch_id musi byt vyplnene")
|
||||||
|
self.train_runner_ids = train_runner_ids
|
||||||
|
self.train_batch_id = train_batch_id
|
||||||
|
#target cílový sloupec, který je používám přímo nebo transformován na binary
|
||||||
|
self.target = target
|
||||||
|
self.target_reference = target_reference
|
||||||
|
self.train_target_steps = train_target_steps
|
||||||
|
self.train_target_transformation = train_target_transformation
|
||||||
|
self.input_sequences = input_sequences
|
||||||
|
self.train_epochs = train_epochs
|
||||||
|
#keep cross sequences between runners
|
||||||
|
self.train_remove_cross_sequences = train_remove_cross_sequences
|
||||||
|
self.scalerX = scalerX
|
||||||
|
self.scalerY = scalerY
|
||||||
|
self.model = model
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
filename = mu.get_full_filename(self.name,self.version)
|
||||||
|
dump(self, filename)
|
||||||
|
print(f"model {self.name} save")
|
||||||
|
|
||||||
|
#create X data with features
|
||||||
|
def column_stack_source(self, bars, indicators, verbose = 1) -> np.array:
|
||||||
|
#create SOURCE DATA with features
|
||||||
|
# bars and indicators dictionary and features as input
|
||||||
|
poradi_sloupcu_inds = [feature for feature in self.ind_features if feature in indicators]
|
||||||
|
indicator_data = np.column_stack([indicators[feature] for feature in self.ind_features if feature in indicators])
|
||||||
|
|
||||||
|
if len(bars)>0:
|
||||||
|
bar_data = np.column_stack([bars[feature] for feature in self.bar_features if feature in bars])
|
||||||
|
poradi_sloupcu_bars = [feature for feature in self.bar_features if feature in bars]
|
||||||
|
if verbose == 1:
|
||||||
|
print("poradi sloupce v source_data", str(poradi_sloupcu_bars + poradi_sloupcu_inds))
|
||||||
|
combined_day_data = np.column_stack([bar_data,indicator_data])
|
||||||
|
else:
|
||||||
|
combined_day_data = indicator_data
|
||||||
|
if verbose == 1:
|
||||||
|
print("poradi sloupce v source_data", str(poradi_sloupcu_inds))
|
||||||
|
return combined_day_data
|
||||||
|
|
||||||
|
#create TARGET(Y) data
|
||||||
|
def column_stack_target(self, bars, indicators) -> np.array:
|
||||||
|
target_base = []
|
||||||
|
target_reference = []
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
target_base = bars[self.target]
|
||||||
|
except KeyError:
|
||||||
|
target_base = indicators[self.target]
|
||||||
|
try:
|
||||||
|
target_reference = bars[self.target_reference]
|
||||||
|
except KeyError:
|
||||||
|
target_reference = indicators[self.target_reference]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
target_day_data = np.column_stack([target_base, target_reference])
|
||||||
|
return target_day_data
|
||||||
|
|
||||||
|
def load_runners_as_list(self, runner_id_list = None, batch_id = None):
|
||||||
|
"""Loads all runners data (bars, indicators) for given runners into list of dicts.
|
||||||
|
|
||||||
|
List of runners/train_batch_id may be provided, or self.train_runner_ids/train_batch_id is taken instead.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
tuple (barslist, indicatorslist,) - lists with dictionaries for each runner
|
||||||
|
"""
|
||||||
|
if runner_id_list is not None:
|
||||||
|
runner_ids = runner_id_list
|
||||||
|
print("loading runners for ",str(runner_id_list))
|
||||||
|
elif batch_id is not None:
|
||||||
|
print("Loading runners for train_batch_id:", batch_id)
|
||||||
|
res, runner_ids = get_archived_runnerslist_byBatchID(batch_id)
|
||||||
|
elif self.train_batch_id is not None:
|
||||||
|
print("Loading runners for TRAINING BATCH self.train_batch_id:", self.train_batch_id)
|
||||||
|
res, runner_ids = get_archived_runnerslist_byBatchID(self.train_batch_id)
|
||||||
|
#pripadne bereme z listu runneru
|
||||||
|
else:
|
||||||
|
runner_ids = self.train_runner_ids
|
||||||
|
print("loading runners for TRAINING runners ",str(self.train_runner_ids))
|
||||||
|
|
||||||
|
|
||||||
|
barslist = []
|
||||||
|
indicatorslist = []
|
||||||
|
ind_keys = None
|
||||||
|
for runner_id in runner_ids:
|
||||||
|
bars, indicators = mu.load_runner(runner_id)
|
||||||
|
print(f"runner:{runner_id}")
|
||||||
|
if self.use_bars:
|
||||||
|
barslist.append(bars)
|
||||||
|
print(f"bars keys {len(bars)} lng {len(bars[self.bar_features[0]])}")
|
||||||
|
indicatorslist.append(indicators)
|
||||||
|
print(f"indi keys {len(indicators)} lng {len(indicators[self.ind_features[0]])}")
|
||||||
|
if ind_keys is not None and ind_keys != len(indicators):
|
||||||
|
raise Exception("V runnerech musi byt stejny pocet indikatoru")
|
||||||
|
else:
|
||||||
|
ind_keys = len(indicators)
|
||||||
|
|
||||||
|
return barslist, indicatorslist
|
||||||
|
|
||||||
|
#toto nejspis rozdelit na TRAIN mod (kdy ma smysl si brat nataveni napr. remove cross)
|
||||||
|
def create_sequences(self, combined_data, target_data = None, remove_cross_sequences: bool = False, rows_in_day = None):
|
||||||
|
"""Creates sequences of given length seq and optionally target N steps in the future.
|
||||||
|
|
||||||
|
Returns X(source) a Y(transformed target) - vrací take Y_untransformed - napr. referencni target column pro zobrazeni v grafu (napr. cenu)
|
||||||
|
|
||||||
|
Volby pro transformaci targetu:
|
||||||
|
- KEEPVAL (keep value as is)
|
||||||
|
- KEEPVAL_MOVE(keep value, move target N steps in the future)
|
||||||
|
|
||||||
|
další na zámysl (nejspíš ale data budu připravovat ve stratu a využívat jen KEEPy nahoře)
|
||||||
|
- BINARY_prefix - sloupec založený na podmínce, výsledek je 0,1
|
||||||
|
- BINARY_TREND RISING - podmínka založena, že v target columnu stoupají/klesají po target N steps
|
||||||
|
(podvarianty BINARY TREND RISING(0-1), FALLING(0-1), BOTH(-1 - ))
|
||||||
|
- BINARY_READY - předpřipravený sloupec(vytvořený ve strategii jako indikator), stačí jen posunout o target step
|
||||||
|
- BINARY_READY_POSUNUTY - předpřipraveny sloupec (již posunutýo o target M) - stačí brát as is
|
||||||
|
|
||||||
|
Args:
|
||||||
|
combined_data: A list of combined data.
|
||||||
|
target_data: A list of target data (0-target,1-target ref.column)
|
||||||
|
remove_cross_sequences: If to remove crossday sequences
|
||||||
|
rows_in_day: helper dict to remove crossday sequences
|
||||||
|
return_untr: whether to return untransformed reference column
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A list of X sequences and a list of y sequences.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if remove_cross_sequences is True and rows_in_day is None:
|
||||||
|
raise Exception("To remove crossday sequences, rows_in_day param required.")
|
||||||
|
|
||||||
|
if target_data is not None and len(target_data) > 0:
|
||||||
|
target_data_untr = target_data[:,1]
|
||||||
|
target_data = target_data[:,0]
|
||||||
|
else:
|
||||||
|
target_data_untr = []
|
||||||
|
target_data = []
|
||||||
|
|
||||||
|
X_train = []
|
||||||
|
y_train = []
|
||||||
|
y_untr = []
|
||||||
|
#comb data shape (4073, 13)
|
||||||
|
#target shape (4073, 1)
|
||||||
|
print("Start Sequencing")
|
||||||
|
#range sekvence podle toho jestli je pozadovan MOVE nebo NE
|
||||||
|
if self.train_target_transformation == TargetTRFM.KEEPVAL_MOVE:
|
||||||
|
right_offset = self.input_sequences + self.train_target_steps
|
||||||
|
else:
|
||||||
|
right_offset= self.input_sequences
|
||||||
|
for i in range(len(combined_data) - right_offset):
|
||||||
|
|
||||||
|
#take neresime cross sekvence kdyz neni vyplneni target nebo neni vyplnena rowsinaday
|
||||||
|
if remove_cross_sequences is True and not self.is_same_day(i,i + right_offset, rows_in_day):
|
||||||
|
print(f"sekvence vyrazena. NEW Zacatek {combined_data[i, 0]} konec {combined_data[i + right_offset, 0]}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
#pridame sekvenci
|
||||||
|
X_train.append(combined_data[i:i + self.input_sequences])
|
||||||
|
|
||||||
|
#target hodnotu bude ponecha (na radku mame jiz cilovy target)
|
||||||
|
#nebo vezme hodnotu z N(train_target_steps) baru vpredu a da jako target k radku
|
||||||
|
#je rizeno nastavenim right_offset vyse
|
||||||
|
if target_data is not None and len(target_data) > 0:
|
||||||
|
y_train.append(target_data[i + right_offset])
|
||||||
|
|
||||||
|
#udela binary transformaci targetu
|
||||||
|
# elif self.target_transformation == TargetTRFM.BINARY_TREND_UP:
|
||||||
|
# #mini loop od 0 do počtu target steps - zda jsou successively rising
|
||||||
|
# #radeji budu resit vizualne conditional indikatorem pri priprave dat
|
||||||
|
# rising = False
|
||||||
|
# for step in range(0,self.train_target_steps):
|
||||||
|
# if target_data[i + self.input_sequences + step] < target_data[i + self.input_sequences + step + 1]:
|
||||||
|
# rising = True
|
||||||
|
# else:
|
||||||
|
# rising = False
|
||||||
|
# break
|
||||||
|
# y_train.append([1] if rising else [0])
|
||||||
|
# #tato zakomentovana varianta porovnava jen cenu ted a cenu na target baru
|
||||||
|
# #y_train.append([1] if target_data[i + self.input_sequences] < target_data[i + self.input_sequences + self.train_target_steps] else [0])
|
||||||
|
if target_data is not None and len(target_data) > 0:
|
||||||
|
y_untr.append(target_data_untr[i + self.input_sequences])
|
||||||
|
return np.array(X_train), np.array(y_train), np.array(y_untr)
|
||||||
|
|
||||||
|
def is_same_day(self, idx_start, idx_end, rows_in_day):
|
||||||
|
"""Helper for sequencing enables to recognize if the start/end index are from the same day.
|
||||||
|
|
||||||
|
Used for sequences to remove cross runner(day) sequences.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
idx_start: Start index
|
||||||
|
idx_end: End index
|
||||||
|
rows_in_day: 1D array containing number of rows(bars,inds) for each day.
|
||||||
|
Cumsumed defines edges where each day ends. [10,30,60]
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A boolean
|
||||||
|
|
||||||
|
refactor to vectors if possible
|
||||||
|
i_b, i_e
|
||||||
|
podm_pole = i_b<pole and i_s >= pole
|
||||||
|
[10,30,60]
|
||||||
|
"""
|
||||||
|
for i in rows_in_day:
|
||||||
|
#jde o polozku na pomezi - vyhazujeme
|
||||||
|
if idx_start < i and idx_end >= i:
|
||||||
|
return False
|
||||||
|
if idx_start < i and idx_end < i:
|
||||||
|
return True
|
||||||
|
return None
|
||||||
|
|
||||||
|
#vytvori X a Y data z nastaveni self
|
||||||
|
#pro vybrane runnery stahne data, vybere sloupce dle faature a target
|
||||||
|
#a vrátí jako sloupce v numpy poli
|
||||||
|
#zaroven vraci i rows_in_day pro nasledny sekvencing
|
||||||
|
def load_data(self, runners_ids: list = None, batch_id: list = None, source: Source = Source.RUNNERS):
|
||||||
|
"""Service to load data for the model. Can be used for training or for vector prediction.
|
||||||
|
|
||||||
|
If input data are not provided, it will get the value from training model configuration (train_runners_ids, train_batch_id)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
runner_ids:
|
||||||
|
batch_id:
|
||||||
|
source: To load sample data.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
source_data,target_data,rows_in_day
|
||||||
|
"""
|
||||||
|
rows_in_day = []
|
||||||
|
indicatorslist = []
|
||||||
|
#bud natahneme samply
|
||||||
|
if source == Source.SAMPLES:
|
||||||
|
if self.use_bars:
|
||||||
|
bars = sample_bars
|
||||||
|
else:
|
||||||
|
bars = {}
|
||||||
|
indicators = sample_indicators
|
||||||
|
indicatorslist.append(indicators)
|
||||||
|
#nebo dotahneme pozadovane runnery
|
||||||
|
else:
|
||||||
|
#nalodujeme vsechny runnery jako listy (bud z runnerids nebo dle batchid)
|
||||||
|
barslist, indicatorslist = self.load_runners_as_list(runner_id_list=runners_ids, batch_id=batch_id)
|
||||||
|
#nerozumim
|
||||||
|
bl = deepcopy(barslist)
|
||||||
|
il = deepcopy(indicatorslist)
|
||||||
|
#a zmergujeme jejich data dohromady
|
||||||
|
bars = mu.merge_dicts(bl)
|
||||||
|
indicators = mu.merge_dicts(il)
|
||||||
|
|
||||||
|
#zaroven vytvarime pomocny list, kde stale drzime pocet radku per day (pro nasledny sekvencing)
|
||||||
|
#zatim nad indikatory - v budoucnu zvazit, kdyby jelo neco jen nad barama
|
||||||
|
for i, val in enumerate(indicatorslist):
|
||||||
|
#pro prvni klic z indikatoru pocteme cnt
|
||||||
|
pocet = len(indicatorslist[i][self.ind_features[0]])
|
||||||
|
print("pro runner vkladame pocet", pocet)
|
||||||
|
rows_in_day.append(pocet)
|
||||||
|
|
||||||
|
rows_in_day = np.array(rows_in_day)
|
||||||
|
rows_in_day = np.cumsum(rows_in_day)
|
||||||
|
print("celkove pole rows_in_day(cumsum):", rows_in_day)
|
||||||
|
|
||||||
|
print("Data LOADED.")
|
||||||
|
print(f"number of indicators {len(indicators)}")
|
||||||
|
print(f"number of bar elements{len(bars)}")
|
||||||
|
print(f"ind list length {len(indicators['time'])}")
|
||||||
|
print(f"bar list length {len(bars['time'])}")
|
||||||
|
|
||||||
|
self.validate_available_features(bars, indicators)
|
||||||
|
|
||||||
|
print("Preparing FEATURES")
|
||||||
|
source_data, target_data = self.stack_bars_indicators(bars, indicators)
|
||||||
|
return source_data, target_data, rows_in_day
|
||||||
|
|
||||||
|
def validate_available_features(self, bars, indicators):
|
||||||
|
for k in self.bar_features:
|
||||||
|
if not k in bars.keys():
|
||||||
|
raise Exception(f"Missing bar feature {k}")
|
||||||
|
|
||||||
|
for k in self.ind_features:
|
||||||
|
if not k in indicators.keys():
|
||||||
|
raise Exception(f"Missing ind feature {k}")
|
||||||
|
|
||||||
|
def stack_bars_indicators(self, bars, indicators):
|
||||||
|
print("Stacking dicts to numpy")
|
||||||
|
print("Source - X")
|
||||||
|
source_data = self.column_stack_source(bars, indicators)
|
||||||
|
print("shape", np.shape(source_data))
|
||||||
|
print("Target - Y", self.target)
|
||||||
|
target_data = self.column_stack_target(bars, indicators)
|
||||||
|
print("shape", np.shape(target_data))
|
||||||
|
|
||||||
|
return source_data, target_data
|
||||||
|
|
||||||
|
#pomocna sluzba, ktera provede vsechny transformace a inverzni scaling a vyleze z nej predikce
|
||||||
|
#vstupem je standardni format ve strategii (state.bars, state.indicators)
|
||||||
|
#vystupem je jedna hodnota
|
||||||
|
def predict(self, bars, indicators) -> float:
|
||||||
|
#oriznuti podle seqence - pokud je nastaveno v modelu
|
||||||
|
lastNbars = slice_dict_lists(bars, self.input_sequences)
|
||||||
|
lastNindicators = slice_dict_lists(indicators, self.input_sequences)
|
||||||
|
# print("last5bars", lastNbars)
|
||||||
|
# print("last5indicators",lastNindicators)
|
||||||
|
|
||||||
|
combined_live_data = self.column_stack_source(lastNbars, lastNindicators, verbose=0)
|
||||||
|
#print("combined_live_data",combined_live_data)
|
||||||
|
combined_live_data = self.scalerX.transform(combined_live_data)
|
||||||
|
combined_live_data = np.array(combined_live_data)
|
||||||
|
#print("last 5 values combined data shape", np.shape(combined_live_data))
|
||||||
|
|
||||||
|
#converts to 3D array
|
||||||
|
# 1 number of samples in the array.
|
||||||
|
# 2 represents the sequence length.
|
||||||
|
# 3 represents the number of features in the data.
|
||||||
|
combined_live_data = combined_live_data.reshape((1, self.input_sequences, combined_live_data.shape[1]))
|
||||||
|
|
||||||
|
# Make a prediction
|
||||||
|
prediction = self.model(combined_live_data, training=False)
|
||||||
|
#prediction = prediction.reshape((1, 1))
|
||||||
|
# Convert the prediction back to the original scale
|
||||||
|
prediction = self.scalerY.inverse_transform(prediction)
|
||||||
|
return float(prediction)
|
||||||
55
v2realbot/ml/mlutils.py
Normal file
55
v2realbot/ml/mlutils.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import numpy as np
|
||||||
|
from v2realbot.controller.services import get_archived_runner_details_byID
|
||||||
|
from joblib import load
|
||||||
|
from v2realbot.config import DATA_DIR
|
||||||
|
|
||||||
|
def get_full_filename(name, version = "1"):
|
||||||
|
return DATA_DIR+'/models/'+name+'_v'+version+'.pkl'
|
||||||
|
|
||||||
|
def load_model(name, version = "1"):
|
||||||
|
filename = get_full_filename(name, version)
|
||||||
|
return load(filename)
|
||||||
|
|
||||||
|
#pomocne funkce na manipulaci s daty
|
||||||
|
|
||||||
|
def merge_dicts(dict_list):
|
||||||
|
# Initialize an empty merged dictionary
|
||||||
|
merged_dict = {}
|
||||||
|
|
||||||
|
# Iterate through the dictionaries in the list
|
||||||
|
for i,d in enumerate(dict_list):
|
||||||
|
for key, value in d.items():
|
||||||
|
if key in merged_dict:
|
||||||
|
merged_dict[key] += value
|
||||||
|
else:
|
||||||
|
merged_dict[key] = value
|
||||||
|
#vlozime element s idenitfikaci runnera
|
||||||
|
|
||||||
|
return merged_dict
|
||||||
|
|
||||||
|
# # Initialize the merged dictionary with the first dictionary in the list
|
||||||
|
# merged_dict = dict_list[0].copy()
|
||||||
|
# merged_dict["index"] = []
|
||||||
|
|
||||||
|
# # Iterate through the remaining dictionaries and concatenate their lists
|
||||||
|
# for i, d in enumerate(dict_list[1:]):
|
||||||
|
# merged_dict["index"] =
|
||||||
|
# for key, value in d.items():
|
||||||
|
# if key in merged_dict:
|
||||||
|
# merged_dict[key] += value
|
||||||
|
# else:
|
||||||
|
# merged_dict[key] = value
|
||||||
|
|
||||||
|
# return merged_dict
|
||||||
|
|
||||||
|
def load_runner(runner_id):
|
||||||
|
res, sada = get_archived_runner_details_byID(runner_id)
|
||||||
|
if res == 0:
|
||||||
|
print("ok")
|
||||||
|
else:
|
||||||
|
print("error",res,sada)
|
||||||
|
raise Exception(f"error loading runner {runner_id} : {res} {sada}")
|
||||||
|
|
||||||
|
bars = sada["bars"]
|
||||||
|
indicators = sada["indicators"][0]
|
||||||
|
return bars, indicators
|
||||||
@ -15,15 +15,28 @@
|
|||||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
|
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
|
||||||
|
|
||||||
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
|
<!-- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous"> -->
|
||||||
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.4/css/dataTables.bootstrap5.min.css">
|
<link href="/static/js/libs/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
|
||||||
|
|
||||||
<script src="https://code.jquery.com/jquery-3.6.4.js" integrity="sha256-a9jBBRygX1Bh5lt8GZjXDzyOB+bWve9EiO7tROUtj/E=" crossorigin="anonymous"></script>
|
|
||||||
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
|
|
||||||
<script src="/static/js/jquery.serializejson.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ENjdO4Dr2bkBIFxQpeoTz1HIcje39Wm4jDKdf19U8gI4ddQ3GYNS7NTKfAdVQSZe" crossorigin="anonymous"></script>
|
|
||||||
|
|
||||||
<script src="https://cdn.datatables.net/select/1.6.2/js/dataTables.select.min.js"></script>
|
<!-- <link rel="stylesheet" href="https://cdn.datatables.net/1.13.4/css/dataTables.bootstrap5.min.css"> -->
|
||||||
|
<link rel="stylesheet" href="/static/js/libs/dataTables.bootstrap5.min.css">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- <script src="https://code.jquery.com/jquery-3.6.4.js" integrity="sha256-a9jBBRygX1Bh5lt8GZjXDzyOB+bWve9EiO7tROUtj/E=" crossorigin="anonymous"></script> -->
|
||||||
|
<script src="/static/js/libs/jquery-3.6.4.js" integrity="sha256-a9jBBRygX1Bh5lt8GZjXDzyOB+bWve9EiO7tROUtj/E=" crossorigin="anonymous"></script>
|
||||||
|
|
||||||
|
<!-- <script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script> -->
|
||||||
|
<script src="/static/js/libs/jquery.dataTables.min.js"></script>
|
||||||
|
|
||||||
|
<script src="/static/js/jquery.serializejson.js"></script>
|
||||||
|
|
||||||
|
<!-- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ENjdO4Dr2bkBIFxQpeoTz1HIcje39Wm4jDKdf19U8gI4ddQ3GYNS7NTKfAdVQSZe" crossorigin="anonymous"></script> -->
|
||||||
|
<script src="/static/js/libs/bootstrap.bundle.min.js" crossorigin="anonymous"></script>
|
||||||
|
|
||||||
|
<!-- <script src="https://cdn.datatables.net/select/1.6.2/js/dataTables.select.min.js"></script> -->
|
||||||
|
<script src="/static/js/libs/dataTables.select.min.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -41,7 +54,10 @@
|
|||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="/static/main.css">
|
<link rel="stylesheet" href="/static/main.css">
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/mousetrap/1.4.6/mousetrap.min.js"></script>
|
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/mousetrap/1.4.6/mousetrap.min.js"></script> -->
|
||||||
|
|
||||||
|
<script src="/static/js/libs/mousetrap.min.js"></script>
|
||||||
|
|
||||||
<!-- <script src="https://cdn.datatables.net/select/1.6.2/js/dataTables.select.min.js"></script> -->
|
<!-- <script src="https://cdn.datatables.net/select/1.6.2/js/dataTables.select.min.js"></script> -->
|
||||||
<script src="/static/js/fast-toml.js" type="text/javascript"></script>
|
<script src="/static/js/fast-toml.js" type="text/javascript"></script>
|
||||||
|
|
||||||
@ -60,8 +76,14 @@
|
|||||||
});
|
});
|
||||||
</script> -->
|
</script> -->
|
||||||
<!-- predelat na local z cdn -->
|
<!-- predelat na local z cdn -->
|
||||||
<link rel="stylesheet" data-name="vs/editor/editor.main" href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.43.0/min/vs/editor/editor.main.min.css">
|
<!-- <link rel="stylesheet" data-name="vs/editor/editor.main" href="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.43.0/min/vs/editor/editor.main.min.css">
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.43.0/min/vs/loader.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.43.0/min/vs/loader.min.js"></script> -->
|
||||||
|
|
||||||
|
<link rel="stylesheet" data-name="vs/editor/editor.main" href="/static/js/libs/editor.main.min.css">
|
||||||
|
<script src="/static/js/libs/loader.min.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.41.0/min/vs/editor/editor.main.js"></script> -->
|
<!-- <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.41.0/min/vs/editor/editor.main.js"></script> -->
|
||||||
<!-- <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.41.0/min/vs/loader.min.js"></script> -->
|
<!-- <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.41.0/min/vs/loader.min.js"></script> -->
|
||||||
@ -522,7 +544,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="mode" class="form-label">Mode</label>
|
<label for="mode" class="form-label">Mode</label>
|
||||||
<select class="form-control" id="mode" name="mode"><option value="paper">paper</option><option value="live">live</option><option value="backtest">backtest</option></select>
|
<select class="form-control" id="mode" name="mode"><option value="paper">paper</option><option value="live">live</option><option value="backtest">backtest</option><option value="prep">prep</option></select>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="account" class="form-label">Account</label>
|
<label for="account" class="form-label">Account</label>
|
||||||
@ -639,7 +661,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="/static/js/config.js"></script>
|
<script src="/static/js/config.js"></script>
|
||||||
<script type="text/javascript" src="https://unpkg.com/lightweight-charts/dist/lightweight-charts.standalone.production.js"></script>
|
<!-- tady zacina polska docasna lokalizace -->
|
||||||
|
<!-- <script type="text/javascript" src="https://unpkg.com/lightweight-charts/dist/lightweight-charts.standalone.production.js"></script> -->
|
||||||
|
<script type="text/javascript" src="/static/js/libs/lightweight-charts.standalone.production.js"></script>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="/static/js/utils.js"></script>
|
<script src="/static/js/utils.js"></script>
|
||||||
<script src="/static/js/archivechart.js"></script>
|
<script src="/static/js/archivechart.js"></script>
|
||||||
<script src="/static/js/archivetables.js"></script>
|
<script src="/static/js/archivetables.js"></script>
|
||||||
|
|||||||
7
v2realbot/static/js/libs/bootstrap.bundle.min.js
vendored
Normal file
7
v2realbot/static/js/libs/bootstrap.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
v2realbot/static/js/libs/bootstrap.min.css
vendored
Normal file
7
v2realbot/static/js/libs/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
1
v2realbot/static/js/libs/content.css
Normal file
1
v2realbot/static/js/libs/content.css
Normal file
File diff suppressed because one or more lines are too long
5
v2realbot/static/js/libs/dataTables.bootstrap5.min.css
vendored
Normal file
5
v2realbot/static/js/libs/dataTables.bootstrap5.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
4
v2realbot/static/js/libs/dataTables.select.min.js
vendored
Normal file
4
v2realbot/static/js/libs/dataTables.select.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
758
v2realbot/static/js/libs/editor.main.js
Normal file
758
v2realbot/static/js/libs/editor.main.js
Normal file
File diff suppressed because one or more lines are too long
6
v2realbot/static/js/libs/editor.main.min.css
vendored
Normal file
6
v2realbot/static/js/libs/editor.main.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
758
v2realbot/static/js/libs/editor/editor.main.js
Normal file
758
v2realbot/static/js/libs/editor/editor.main.js
Normal file
File diff suppressed because one or more lines are too long
758
v2realbot/static/js/libs/editor/editor.main.nls.js
Normal file
758
v2realbot/static/js/libs/editor/editor.main.nls.js
Normal file
File diff suppressed because one or more lines are too long
10965
v2realbot/static/js/libs/jquery-3.6.4.js
vendored
Normal file
10965
v2realbot/static/js/libs/jquery-3.6.4.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4
v2realbot/static/js/libs/jquery.dataTables.min.js
vendored
Normal file
4
v2realbot/static/js/libs/jquery.dataTables.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
15
v2realbot/static/js/libs/jsonMode.js
Normal file
15
v2realbot/static/js/libs/jsonMode.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4
v2realbot/static/js/libs/loader.min.js
vendored
Normal file
4
v2realbot/static/js/libs/loader.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
9
v2realbot/static/js/libs/mousetrap.min.js
vendored
Normal file
9
v2realbot/static/js/libs/mousetrap.min.js
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/* mousetrap v1.4.6 craig.is/killing/mice */
|
||||||
|
(function(J,r,f){function s(a,b,d){a.addEventListener?a.addEventListener(b,d,!1):a.attachEvent("on"+b,d)}function A(a){if("keypress"==a.type){var b=String.fromCharCode(a.which);a.shiftKey||(b=b.toLowerCase());return b}return h[a.which]?h[a.which]:B[a.which]?B[a.which]:String.fromCharCode(a.which).toLowerCase()}function t(a){a=a||{};var b=!1,d;for(d in n)a[d]?b=!0:n[d]=0;b||(u=!1)}function C(a,b,d,c,e,v){var g,k,f=[],h=d.type;if(!l[a])return[];"keyup"==h&&w(a)&&(b=[a]);for(g=0;g<l[a].length;++g)if(k=
|
||||||
|
l[a][g],!(!c&&k.seq&&n[k.seq]!=k.level||h!=k.action||("keypress"!=h||d.metaKey||d.ctrlKey)&&b.sort().join(",")!==k.modifiers.sort().join(","))){var m=c&&k.seq==c&&k.level==v;(!c&&k.combo==e||m)&&l[a].splice(g,1);f.push(k)}return f}function K(a){var b=[];a.shiftKey&&b.push("shift");a.altKey&&b.push("alt");a.ctrlKey&&b.push("ctrl");a.metaKey&&b.push("meta");return b}function x(a,b,d,c){m.stopCallback(b,b.target||b.srcElement,d,c)||!1!==a(b,d)||(b.preventDefault?b.preventDefault():b.returnValue=!1,b.stopPropagation?
|
||||||
|
b.stopPropagation():b.cancelBubble=!0)}function y(a){"number"!==typeof a.which&&(a.which=a.keyCode);var b=A(a);b&&("keyup"==a.type&&z===b?z=!1:m.handleKey(b,K(a),a))}function w(a){return"shift"==a||"ctrl"==a||"alt"==a||"meta"==a}function L(a,b,d,c){function e(b){return function(){u=b;++n[a];clearTimeout(D);D=setTimeout(t,1E3)}}function v(b){x(d,b,a);"keyup"!==c&&(z=A(b));setTimeout(t,10)}for(var g=n[a]=0;g<b.length;++g){var f=g+1===b.length?v:e(c||E(b[g+1]).action);F(b[g],f,c,a,g)}}function E(a,b){var d,
|
||||||
|
c,e,f=[];d="+"===a?["+"]:a.split("+");for(e=0;e<d.length;++e)c=d[e],G[c]&&(c=G[c]),b&&"keypress"!=b&&H[c]&&(c=H[c],f.push("shift")),w(c)&&f.push(c);d=c;e=b;if(!e){if(!p){p={};for(var g in h)95<g&&112>g||h.hasOwnProperty(g)&&(p[h[g]]=g)}e=p[d]?"keydown":"keypress"}"keypress"==e&&f.length&&(e="keydown");return{key:c,modifiers:f,action:e}}function F(a,b,d,c,e){q[a+":"+d]=b;a=a.replace(/\s+/g," ");var f=a.split(" ");1<f.length?L(a,f,b,d):(d=E(a,d),l[d.key]=l[d.key]||[],C(d.key,d.modifiers,{type:d.action},
|
||||||
|
c,a,e),l[d.key][c?"unshift":"push"]({callback:b,modifiers:d.modifiers,action:d.action,seq:c,level:e,combo:a}))}var h={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",18:"alt",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},B={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},H={"~":"`","!":"1",
|
||||||
|
"@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},G={option:"alt",command:"meta","return":"enter",escape:"esc",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},p,l={},q={},n={},D,z=!1,I=!1,u=!1;for(f=1;20>f;++f)h[111+f]="f"+f;for(f=0;9>=f;++f)h[f+96]=f;s(r,"keypress",y);s(r,"keydown",y);s(r,"keyup",y);var m={bind:function(a,b,d){a=a instanceof Array?a:[a];for(var c=0;c<a.length;++c)F(a[c],b,d);return this},
|
||||||
|
unbind:function(a,b){return m.bind(a,function(){},b)},trigger:function(a,b){if(q[a+":"+b])q[a+":"+b]({},a);return this},reset:function(){l={};q={};return this},stopCallback:function(a,b){return-1<(" "+b.className+" ").indexOf(" mousetrap ")?!1:"INPUT"==b.tagName||"SELECT"==b.tagName||"TEXTAREA"==b.tagName||b.isContentEditable},handleKey:function(a,b,d){var c=C(a,b,d),e;b={};var f=0,g=!1;for(e=0;e<c.length;++e)c[e].seq&&(f=Math.max(f,c[e].level));for(e=0;e<c.length;++e)c[e].seq?c[e].level==f&&(g=!0,
|
||||||
|
b[c[e].seq]=1,x(c[e].callback,d,c[e].combo,c[e].seq)):g||x(c[e].callback,d,c[e].combo);c="keypress"==d.type&&I;d.type!=u||w(a)||c||t(b);I=g&&"keydown"==d.type}};J.Mousetrap=m;"function"===typeof define&&define.amd&&define(m)})(window,document);
|
||||||
@ -12,7 +12,7 @@ function get_status(id) {
|
|||||||
//window.alert(JSON.stringify(data))
|
//window.alert(JSON.stringify(data))
|
||||||
if (data.strat_id == id) {
|
if (data.strat_id == id) {
|
||||||
//window.alert("found");
|
//window.alert("found");
|
||||||
if ((data.run_mode) == "backtest") { status_detail = '<span>'+data.run_mode+'</span>'}
|
if (((data.run_mode) == "backtest") || ((data.run_mode) == "prep")) { status_detail = '<span>'+data.run_mode+'</span>'}
|
||||||
else { status_detail = data.run_mode + " | " + data.run_account}
|
else { status_detail = data.run_mode + " | " + data.run_account}
|
||||||
if (data.run_paused == null) {
|
if (data.run_paused == null) {
|
||||||
status = '<span class="material-symbols-outlined">play_circle</span>'+status_detail
|
status = '<span class="material-symbols-outlined">play_circle</span>'+status_detail
|
||||||
@ -44,8 +44,9 @@ let editor;
|
|||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
|
|
||||||
//incialize TOML LANGUAGE IN MONACO
|
//incialize TOML LANGUAGE IN MONACO
|
||||||
require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.43.0/min/vs' }});
|
// require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.43.0/min/vs' }});
|
||||||
|
require.config({ paths: { 'vs': '/static/js/libs' }});
|
||||||
|
|
||||||
require(["vs/editor/editor.main"], () => {
|
require(["vs/editor/editor.main"], () => {
|
||||||
|
|
||||||
// Register the TOML language
|
// Register the TOML language
|
||||||
|
|||||||
@ -15,7 +15,7 @@ from alpaca.common.exceptions import APIError
|
|||||||
import copy
|
import copy
|
||||||
from threading import Event
|
from threading import Event
|
||||||
from uuid import UUID, uuid4
|
from uuid import UUID, uuid4
|
||||||
|
from v2realbot.strategyblocks.indicators.indicators_hub import populate_all_indicators
|
||||||
|
|
||||||
class StrategyClassicSL(Strategy):
|
class StrategyClassicSL(Strategy):
|
||||||
"""
|
"""
|
||||||
@ -229,6 +229,18 @@ class StrategyClassicSL(Strategy):
|
|||||||
self.state.buy = self.buy
|
self.state.buy = self.buy
|
||||||
self.state.sell = self.sell
|
self.state.sell = self.sell
|
||||||
|
|
||||||
|
self.init(self.state)
|
||||||
|
|
||||||
|
def call_next(self, item):
|
||||||
|
#MAIN INDICATORS
|
||||||
|
populate_all_indicators(item, self.state)
|
||||||
|
|
||||||
|
#pro přípravu dat next nevoláme
|
||||||
|
if self.mode == Mode.PREP:
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
self.next(item, self.state)
|
||||||
|
|
||||||
#overidden methods
|
#overidden methods
|
||||||
# pouziva se pri vstupu long nebo exitu short
|
# pouziva se pri vstupu long nebo exitu short
|
||||||
# osetrit uzavreni s vice nez mam
|
# osetrit uzavreni s vice nez mam
|
||||||
@ -278,13 +290,4 @@ class StrategyClassicSL(Strategy):
|
|||||||
#self.state.vars.lastbuyindex = self.state.bars['index'][-1]
|
#self.state.vars.lastbuyindex = self.state.bars['index'][-1]
|
||||||
#self.state.ilog(e="send MARKET SELL to if", msg="S:"+str(size), ltp=self.state.interface.get_last_price(self.state.symbol))
|
#self.state.ilog(e="send MARKET SELL to if", msg="S:"+str(size), ltp=self.state.interface.get_last_price(self.state.symbol))
|
||||||
self.state.ilog(e="send MARKET SELL to if", msg="S:"+str(size), ltp=self.state.bars['close'][-1])
|
self.state.ilog(e="send MARKET SELL to if", msg="S:"+str(size), ltp=self.state.bars['close'][-1])
|
||||||
return self.state.interface.sell(size=size)
|
return self.state.interface.sell(size=size)
|
||||||
|
|
||||||
async def get_limitka_price(self):
|
|
||||||
def_profit = safe_get(self.state.vars, "def_profit")
|
|
||||||
if def_profit == None: def_profit = self.state.vars.profit
|
|
||||||
cena = float(self.state.avgp)
|
|
||||||
if await self.is_defensive_mode():
|
|
||||||
return price2dec(cena+get_tick(cena,float(def_profit)))
|
|
||||||
else:
|
|
||||||
return price2dec(cena+get_tick(cena,float(self.state.vars.profit)))
|
|
||||||
@ -118,14 +118,25 @@ class Strategy:
|
|||||||
self.state = StrategyState(name=self.name, symbol = self.symbol, stratvars = self.stratvars, interface=self.interface, rectype=self.rectype, runner_id=self.runner_id, ilog_save=self.ilog_save)
|
self.state = StrategyState(name=self.name, symbol = self.symbol, stratvars = self.stratvars, interface=self.interface, rectype=self.rectype, runner_id=self.runner_id, ilog_save=self.ilog_save)
|
||||||
|
|
||||||
elif mode == Mode.BT:
|
elif mode == Mode.BT:
|
||||||
|
|
||||||
self.dataloader = Trade_Offline_Streamer(start, end, btdata=self.btdata)
|
self.dataloader = Trade_Offline_Streamer(start, end, btdata=self.btdata)
|
||||||
self.bt = Backtester(symbol = self.symbol, order_fill_callback= self.order_updates, btdata=self.btdata, cash=cash, bp_from=start, bp_to=end)
|
self.bt = Backtester(symbol = self.symbol, order_fill_callback= self.order_updates, btdata=self.btdata, cash=cash, bp_from=start, bp_to=end)
|
||||||
|
|
||||||
self.interface = BacktestInterface(symbol=self.symbol, bt=self.bt)
|
self.interface = BacktestInterface(symbol=self.symbol, bt=self.bt)
|
||||||
self.state = StrategyState(name=self.name, symbol = self.symbol, stratvars = self.stratvars, interface=self.interface, rectype=self.rectype, runner_id=self.runner_id, bt=self.bt, ilog_save=self.ilog_save)
|
self.state = StrategyState(name=self.name, symbol = self.symbol, stratvars = self.stratvars, interface=self.interface, rectype=self.rectype, runner_id=self.runner_id, bt=self.bt, ilog_save=self.ilog_save)
|
||||||
self.order_notifs = None
|
self.order_notifs = None
|
||||||
|
|
||||||
##streamer bude plnit trady do listu trades - nad kterym bude pracovat paper trade
|
##streamer bude plnit trady do listu trades - nad kterym bude pracovat paper trade
|
||||||
#zatim takto - pak pripadne do fajlu nebo jinak OPTIMALIZOVAT
|
#zatim takto - pak pripadne do fajlu nebo jinak OPTIMALIZOVAT
|
||||||
self.dataloader.add_stream(TradeAggregator2List(symbol=self.symbol,btdata=self.btdata,rectype=RecordType.TRADE))
|
self.dataloader.add_stream(TradeAggregator2List(symbol=self.symbol,btdata=self.btdata,rectype=RecordType.TRADE))
|
||||||
|
elif mode == Mode.PREP:
|
||||||
|
#bt je zde jen pro udrzeni BT casu v logu atp. JInak jej nepouzivame.
|
||||||
|
self.bt = Backtester(symbol = self.symbol, order_fill_callback= self.order_updates, btdata=self.btdata, cash=cash, bp_from=start, bp_to=end)
|
||||||
|
self.interface = None
|
||||||
|
#self.interface = BacktestInterface(symbol=self.symbol, bt=self.bt)
|
||||||
|
self.state = StrategyState(name=self.name, symbol = self.symbol, stratvars = self.stratvars, interface=self.interface, rectype=self.rectype, runner_id=self.runner_id, bt=self.bt, ilog_save=self.ilog_save)
|
||||||
|
self.order_notifs = None
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print("unknow mode")
|
print("unknow mode")
|
||||||
return -1
|
return -1
|
||||||
@ -271,7 +282,7 @@ class Strategy:
|
|||||||
self.state.last_trade_time = item['updated']
|
self.state.last_trade_time = item['updated']
|
||||||
elif self.rectype == RecordType.TRADE:
|
elif self.rectype == RecordType.TRADE:
|
||||||
self.state.last_trade_time = item['t']
|
self.state.last_trade_time = item['t']
|
||||||
if self.mode == Mode.BT:
|
if self.mode == Mode.BT or self.mode == Mode.PREP:
|
||||||
self.bt.time = self.state.last_trade_time + BT_DELAYS.trigger_to_strat
|
self.bt.time = self.state.last_trade_time + BT_DELAYS.trigger_to_strat
|
||||||
self.state.time = self.state.last_trade_time + BT_DELAYS.trigger_to_strat
|
self.state.time = self.state.last_trade_time + BT_DELAYS.trigger_to_strat
|
||||||
elif self.mode == Mode.LIVE or self.mode == Mode.PAPER:
|
elif self.mode == Mode.LIVE or self.mode == Mode.PAPER:
|
||||||
@ -319,7 +330,11 @@ class Strategy:
|
|||||||
|
|
||||||
self.save_item_history(item)
|
self.save_item_history(item)
|
||||||
#nevyhodit ten refresh do TypeLimit? asi ANO
|
#nevyhodit ten refresh do TypeLimit? asi ANO
|
||||||
self.refresh_positions(item)
|
|
||||||
|
#pro prep nedelame refresh pozic
|
||||||
|
if self.mode != Mode.PREP:
|
||||||
|
self.refresh_positions(item)
|
||||||
|
|
||||||
#calling plugin (can be overriden to do some additional steps)
|
#calling plugin (can be overriden to do some additional steps)
|
||||||
self.before_iteration()
|
self.before_iteration()
|
||||||
ted = datetime.fromtimestamp(self.state.time).astimezone(zoneNY)
|
ted = datetime.fromtimestamp(self.state.time).astimezone(zoneNY)
|
||||||
@ -331,11 +346,16 @@ class Strategy:
|
|||||||
# Profile the function
|
# Profile the function
|
||||||
if PROFILING_NEXT_ENABLED:
|
if PROFILING_NEXT_ENABLED:
|
||||||
profiler.start()
|
profiler.start()
|
||||||
self.next(item, self.state)
|
#presunuti do samostatne funkce, kvuli overridu
|
||||||
|
self.call_next(item)
|
||||||
if PROFILING_NEXT_ENABLED:
|
if PROFILING_NEXT_ENABLED:
|
||||||
profiler.stop()
|
profiler.stop()
|
||||||
self.after_iteration(item)
|
self.after_iteration(item)
|
||||||
|
|
||||||
|
#toto si mohu ve strategy classe overridnout a pridat dalsi kroky
|
||||||
|
def call_next(self, item):
|
||||||
|
self.next(item, self.state)
|
||||||
|
|
||||||
##run strategy live
|
##run strategy live
|
||||||
def start(self):
|
def start(self):
|
||||||
|
|
||||||
@ -349,12 +369,12 @@ class Strategy:
|
|||||||
if self.mode == Mode.LIVE or self.mode == Mode.PAPER:
|
if self.mode == Mode.LIVE or self.mode == Mode.PAPER:
|
||||||
#live notification thread
|
#live notification thread
|
||||||
self.order_notifs.start()
|
self.order_notifs.start()
|
||||||
else:
|
elif self.mode == Mode.BT or self.mode == Mode.PREP:
|
||||||
self.bt.backtest_start = datetime.now()
|
self.bt.backtest_start = datetime.now()
|
||||||
|
|
||||||
self.strat_init()
|
self.strat_init()
|
||||||
#print(self.init)
|
#print(self.init)
|
||||||
self.init(self.state)
|
|
||||||
|
|
||||||
#main strat loop
|
#main strat loop
|
||||||
print(self.name, "Waiting for DATA")
|
print(self.name, "Waiting for DATA")
|
||||||
@ -433,8 +453,6 @@ class Strategy:
|
|||||||
|
|
||||||
#get rid of attributes that are links to the models
|
#get rid of attributes that are links to the models
|
||||||
self.state.vars["loaded_models"] = {}
|
self.state.vars["loaded_models"] = {}
|
||||||
self.state.vars["loaded_scalersX"] = {}
|
|
||||||
self.state.vars["loaded_scalersY"] = {}
|
|
||||||
|
|
||||||
#zavolame na loaderu remove streamer - mohou byt dalsi bezici strategie, ktery loader vyuzivaji
|
#zavolame na loaderu remove streamer - mohou byt dalsi bezici strategie, ktery loader vyuzivaji
|
||||||
#pripadne udelat shared loader a nebo dedicated loader
|
#pripadne udelat shared loader a nebo dedicated loader
|
||||||
@ -494,7 +512,7 @@ class Strategy:
|
|||||||
|
|
||||||
# inicializace poplatna typu strategie (např. u LIMITu dotažení existující limitky)
|
# inicializace poplatna typu strategie (např. u LIMITu dotažení existující limitky)
|
||||||
def strat_init(self):
|
def strat_init(self):
|
||||||
pass
|
self.init(self.state)
|
||||||
|
|
||||||
def send_rt_updates(self, item):
|
def send_rt_updates(self, item):
|
||||||
##if real time chart is requested
|
##if real time chart is requested
|
||||||
@ -699,7 +717,7 @@ class StrategyState:
|
|||||||
self.time = datetime.now().timestamp()
|
self.time = datetime.now().timestamp()
|
||||||
|
|
||||||
#pri backtestingu logujeme BT casem (muze byt jiny nez self.time - napr. pri notifikacich a naslednych akcích)
|
#pri backtestingu logujeme BT casem (muze byt jiny nez self.time - napr. pri notifikacich a naslednych akcích)
|
||||||
if self.mode == Mode.BT:
|
if self.mode == Mode.BT or self.mode == Mode.PREP:
|
||||||
time = self.bt.time
|
time = self.bt.time
|
||||||
else:
|
else:
|
||||||
time = self.time
|
time = self.time
|
||||||
|
|||||||
0
v2realbot/strategyblocks/__init__.py
Normal file
0
v2realbot/strategyblocks/__init__.py
Normal file
9
v2realbot/strategyblocks/activetrade/activetrade_hub.py
Normal file
9
v2realbot/strategyblocks/activetrade/activetrade_hub.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
from v2realbot.strategyblocks.activetrade.sl.trailsl import trail_SL_management
|
||||||
|
from v2realbot.strategyblocks.activetrade.close.evaluate_close import eval_close_position
|
||||||
|
|
||||||
|
def manage_active_trade(state, data):
|
||||||
|
trade = state.vars.activeTrade
|
||||||
|
if trade is None:
|
||||||
|
return -1
|
||||||
|
trail_SL_management(state, data)
|
||||||
|
eval_close_position(state, data)
|
||||||
45
v2realbot/strategyblocks/activetrade/close/close_position.py
Normal file
45
v2realbot/strategyblocks/activetrade/close/close_position.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.strategy.StrategyOrderLimitVykladaciNormalizedMYSELL import StrategyOrderLimitVykladaciNormalizedMYSELL
|
||||||
|
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, Followup
|
||||||
|
from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus
|
||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.utils.directive_utils import get_conditions_from_configuration
|
||||||
|
from v2realbot.ml.mlutils import load_model
|
||||||
|
from v2realbot.common.model import SLHistory
|
||||||
|
from v2realbot.config import KW
|
||||||
|
from uuid import uuid4
|
||||||
|
from datetime import datetime
|
||||||
|
#import random
|
||||||
|
import json
|
||||||
|
import numpy as np
|
||||||
|
#from icecream import install, ic
|
||||||
|
from rich import print as printanyway
|
||||||
|
from threading import Event
|
||||||
|
import os
|
||||||
|
from traceback import format_exc
|
||||||
|
from v2realbot.strategyblocks.activetrade.helpers import insert_SL_history
|
||||||
|
|
||||||
|
# - close means change status in prescribed Trends,update profit, delete from activeTrade
|
||||||
|
def close_position(state, data, direction: TradeDirection, reason: str, followup: Followup = None):
|
||||||
|
followup_text = str(followup) if followup is not None else ""
|
||||||
|
state.ilog(lvl=1,e=f"CLOSING TRADE {followup_text} {reason} {str(direction)}", curr_price=data["close"], trade=state.vars.activeTrade)
|
||||||
|
if direction == TradeDirection.SHORT:
|
||||||
|
res = state.buy(size=abs(int(state.positions)))
|
||||||
|
if isinstance(res, int) and res < 0:
|
||||||
|
raise Exception(f"error in required operation {reason} {res}")
|
||||||
|
|
||||||
|
elif direction == TradeDirection.LONG:
|
||||||
|
res = state.sell(size=state.positions)
|
||||||
|
if isinstance(res, int) and res < 0:
|
||||||
|
raise Exception(f"error in required operation STOPLOSS SELL {res}")
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise Exception(f"unknow TradeDirection in close_position")
|
||||||
|
|
||||||
|
#pri uzavreni tradu zapisujeme SL history - lepsi zorbazeni v grafu
|
||||||
|
insert_SL_history(state)
|
||||||
|
state.vars.pending = state.vars.activeTrade.id
|
||||||
|
state.vars.activeTrade = None
|
||||||
|
state.vars.last_exit_index = data["index"]
|
||||||
|
if followup is not None:
|
||||||
|
state.vars.requested_followup = followup
|
||||||
172
v2realbot/strategyblocks/activetrade/close/conditions.py
Normal file
172
v2realbot/strategyblocks/activetrade/close/conditions.py
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.strategy.StrategyOrderLimitVykladaciNormalizedMYSELL import StrategyOrderLimitVykladaciNormalizedMYSELL
|
||||||
|
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, Followup
|
||||||
|
from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus
|
||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.utils.directive_utils import get_conditions_from_configuration
|
||||||
|
from v2realbot.ml.mlutils import load_model
|
||||||
|
from v2realbot.common.model import SLHistory
|
||||||
|
from v2realbot.config import KW
|
||||||
|
#from icecream import install, ic
|
||||||
|
from rich import print as printanyway
|
||||||
|
from threading import Event
|
||||||
|
import os
|
||||||
|
from traceback import format_exc
|
||||||
|
from v2realbot.strategyblocks.indicators.helpers import evaluate_directive_conditions
|
||||||
|
from v2realbot.strategyblocks.activetrade.helpers import get_override_for_active_trade, normalize_tick
|
||||||
|
|
||||||
|
def dontexit_protection_met(state, data, direction: TradeDirection):
|
||||||
|
if direction == TradeDirection.LONG:
|
||||||
|
smer = "long"
|
||||||
|
else:
|
||||||
|
smer = "short"
|
||||||
|
|
||||||
|
mother_signal = state.vars.activeTrade.generated_by
|
||||||
|
|
||||||
|
if mother_signal is not None:
|
||||||
|
#TESTUJEME DONT_EXIT_
|
||||||
|
cond_dict = state.vars.conditions[KW.dont_exit][mother_signal][smer]
|
||||||
|
#OR
|
||||||
|
result, conditions_met = evaluate_directive_conditions(state, cond_dict, "OR")
|
||||||
|
state.ilog(lvl=1,e=f"DONT_EXIT {mother_signal} {smer} =OR= {result}", **conditions_met, cond_dict=cond_dict)
|
||||||
|
if result:
|
||||||
|
return True
|
||||||
|
|
||||||
|
#OR neprosly testujeme AND
|
||||||
|
result, conditions_met = evaluate_directive_conditions(state, cond_dict, "AND")
|
||||||
|
state.ilog(lvl=1,e=f"DONT_EXIT {mother_signal} {smer} =AND= {result}", **conditions_met, cond_dict=cond_dict)
|
||||||
|
if result:
|
||||||
|
return True
|
||||||
|
|
||||||
|
cond_dict = state.vars.conditions[KW.dont_exit]["common"][smer]
|
||||||
|
#OR
|
||||||
|
result, conditions_met = evaluate_directive_conditions(state, cond_dict, "OR")
|
||||||
|
state.ilog(lvl=1,e=f"DONT_EXIT common {smer} =OR= {result}", **conditions_met, cond_dict=cond_dict)
|
||||||
|
if result:
|
||||||
|
return True
|
||||||
|
|
||||||
|
#OR neprosly testujeme AND
|
||||||
|
result, conditions_met = evaluate_directive_conditions(state, cond_dict, "AND")
|
||||||
|
state.ilog(lvl=1,e=f"DONT_EXIT common {smer} =AND= {result}", **conditions_met, cond_dict=cond_dict)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def exit_conditions_met(state, data, direction: TradeDirection):
|
||||||
|
if direction == TradeDirection.LONG:
|
||||||
|
smer = "long"
|
||||||
|
else:
|
||||||
|
smer = "short"
|
||||||
|
|
||||||
|
directive_name = "exit_cond_only_on_confirmed"
|
||||||
|
exit_cond_only_on_confirmed = get_override_for_active_trade(state, directive_name=directive_name, default_value=safe_get(state.vars, directive_name, False))
|
||||||
|
|
||||||
|
if exit_cond_only_on_confirmed and data['confirmed'] == 0:
|
||||||
|
state.ilog(lvl=0,e="EXIT COND ONLY ON CONFIRMED BAR")
|
||||||
|
return False
|
||||||
|
|
||||||
|
## minimální počet barů od vstupu
|
||||||
|
directive_name = "exit_cond_req_bars"
|
||||||
|
exit_cond_req_bars = get_override_for_active_trade(state, directive_name=directive_name, default_value=safe_get(state.vars, directive_name, 1))
|
||||||
|
|
||||||
|
if state.vars.last_in_index is not None:
|
||||||
|
index_to_compare = int(state.vars.last_in_index)+int(exit_cond_req_bars)
|
||||||
|
if int(data["index"]) < index_to_compare:
|
||||||
|
state.ilog(lvl=1,e=f"EXIT COND WAITING on required bars from IN {exit_cond_req_bars} TOO SOON", currindex=data["index"], index_to_compare=index_to_compare, last_in_index=state.vars.last_in_index)
|
||||||
|
return False
|
||||||
|
|
||||||
|
#POKUD je nastaven MIN PROFIT, zkontrolujeme ho a az pripadne pustime CONDITIONY
|
||||||
|
directive_name = "exit_cond_min_profit"
|
||||||
|
exit_cond_min_profit_nodir = get_override_for_active_trade(state, directive_name=directive_name, default_value=safe_get(state.vars, directive_name, None))
|
||||||
|
|
||||||
|
directive_name = "exit_cond_min_profit_" + str(smer)
|
||||||
|
exit_cond_min_profit = get_override_for_active_trade(state, directive_name=directive_name, default_value=exit_cond_min_profit_nodir)
|
||||||
|
|
||||||
|
|
||||||
|
#máme nastavený exit_cond_min_profit
|
||||||
|
# zjistíme, zda jsme v daném profit a případně nepustíme dál
|
||||||
|
# , zjistíme aktuální cenu a přičteme k avgp tento profit a podle toho pustime dal
|
||||||
|
|
||||||
|
if exit_cond_min_profit is not None:
|
||||||
|
exit_cond_min_profit_normalized = normalize_tick(state, data, float(exit_cond_min_profit))
|
||||||
|
exit_cond_goal_price = price2dec(float(state.avgp)+exit_cond_min_profit_normalized,3) if int(state.positions) > 0 else price2dec(float(state.avgp)-exit_cond_min_profit_normalized,3)
|
||||||
|
curr_price = float(data["close"])
|
||||||
|
state.ilog(lvl=1,e=f"EXIT COND min profit {exit_cond_goal_price=} {exit_cond_min_profit=} {exit_cond_min_profit_normalized=} {curr_price=}")
|
||||||
|
if (int(state.positions) < 0 and curr_price<=exit_cond_goal_price) or (int(state.positions) > 0 and curr_price>=exit_cond_goal_price):
|
||||||
|
state.ilog(lvl=1,e=f"EXIT COND min profit PASS - POKRACUJEME")
|
||||||
|
else:
|
||||||
|
state.ilog(lvl=1,e=f"EXIT COND min profit NOT PASS")
|
||||||
|
return False
|
||||||
|
|
||||||
|
#TOTO ZATIM NEMA VYZNAM
|
||||||
|
# options = safe_get(state.vars, 'exit_conditions', None)
|
||||||
|
# if options is None:
|
||||||
|
# state.ilog(lvl=0,e="No options for exit conditions in stratvars")
|
||||||
|
# return False
|
||||||
|
|
||||||
|
# disable_exit_proteciton_when = dict(AND=dict(), OR=dict())
|
||||||
|
|
||||||
|
# #preconditions
|
||||||
|
# disable_exit_proteciton_when['disabled_in_config'] = safe_get(options, 'enabled', False) is False
|
||||||
|
# #too good to be true (maximum profit)
|
||||||
|
# #disable_sell_proteciton_when['tgtbt_reached'] = safe_get(options, 'tgtbt', False) is False
|
||||||
|
# disable_exit_proteciton_when['disable_if_positions_above'] = int(safe_get(options, 'disable_if_positions_above', 0)) < abs(int(state.positions))
|
||||||
|
|
||||||
|
# #testing preconditions
|
||||||
|
# result, conditions_met = eval_cond_dict(disable_exit_proteciton_when)
|
||||||
|
# if result:
|
||||||
|
# state.ilog(lvl=0,e=f"EXIT_CONDITION for{smer} DISABLED by {conditions_met}", **conditions_met)
|
||||||
|
# return False
|
||||||
|
|
||||||
|
#bereme bud exit condition signalu, ktery activeTrade vygeneroval+ fallback na general
|
||||||
|
state.ilog(lvl=0,e=f"EXIT CONDITIONS ENTRY {smer}", conditions=state.vars.conditions[KW.exit])
|
||||||
|
|
||||||
|
mother_signal = state.vars.activeTrade.generated_by
|
||||||
|
|
||||||
|
if mother_signal is not None:
|
||||||
|
cond_dict = state.vars.conditions[KW.exit][state.vars.activeTrade.generated_by][smer]
|
||||||
|
result, conditions_met = evaluate_directive_conditions(state, cond_dict, "OR")
|
||||||
|
state.ilog(lvl=1,e=f"EXIT CONDITIONS of {mother_signal} =OR= {result}", **conditions_met, cond_dict=cond_dict)
|
||||||
|
if result:
|
||||||
|
return True
|
||||||
|
|
||||||
|
#OR neprosly testujeme AND
|
||||||
|
result, conditions_met = evaluate_directive_conditions(state, cond_dict, "AND")
|
||||||
|
state.ilog(lvl=1,e=f"EXIT CONDITIONS of {mother_signal} =AND= {result}", **conditions_met, cond_dict=cond_dict)
|
||||||
|
if result:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
#pokud nemame mother signal nebo exit nevratil nic, fallback na common
|
||||||
|
cond_dict = state.vars.conditions[KW.exit]["common"][smer]
|
||||||
|
result, conditions_met = evaluate_directive_conditions(state, cond_dict, "OR")
|
||||||
|
state.ilog(lvl=1,e=f"EXIT CONDITIONS of COMMON =OR= {result}", **conditions_met, cond_dict=cond_dict)
|
||||||
|
if result:
|
||||||
|
return True
|
||||||
|
|
||||||
|
#OR neprosly testujeme AND
|
||||||
|
result, conditions_met = evaluate_directive_conditions(state, cond_dict, "AND")
|
||||||
|
state.ilog(lvl=1,e=f"EXIT CONDITIONS of COMMON =AND= {result}", **conditions_met, cond_dict=cond_dict)
|
||||||
|
if result:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
#ZVAZIT JESTLI nesledujici puvodni pravidlo pro dontsellwhen pujdou realizovat inverzne jako exit when
|
||||||
|
#PUVODNI NASTAVENI - IDENTIFIKOVAce rustoveho MOMENTA - pokud je momentum, tak prodávat později
|
||||||
|
|
||||||
|
# #pokud je slope too high, pak prodavame jakmile slopeMA zacne klesat, napr. 4MA (TODO 3)
|
||||||
|
|
||||||
|
# #TODO zkusit pro pevny profit, jednoduse pozdrzet prodej - dokud tick_price roste nebo se drzi tak neprodavat, pokud klesne prodat
|
||||||
|
# #mozna mit dva mody - pri vetsi volatilite pouzivat momentum, pri mensi nebo kdyz potrebuju pryc, tak prodat hned
|
||||||
|
|
||||||
|
#puvodni nastaveni
|
||||||
|
#slopeMA_rising = 2
|
||||||
|
#rsi_not_falling = 3
|
||||||
|
|
||||||
|
# #toto docasne pryc dont_sell_when['slope_too_high'] = slope_too_high() and not isfalling(state.indicators.slopeMA,4)
|
||||||
|
# dont_sell_when['AND']['slopeMA_rising'] = isrising(state.indicators.slopeMA,safe_get(options, 'slopeMA_rising', 2))
|
||||||
|
# dont_sell_when['AND']['rsi_not_falling'] = not isfalling(state.indicators.RSI14,safe_get(options, 'rsi_not_falling',3))
|
||||||
|
# #dont_sell_when['rsi_dont_buy'] = state.indicators.RSI14[-1] > safe_get(state.vars, "rsi_dont_buy_above",50)
|
||||||
|
|
||||||
|
# result, conditions_met = eval_cond_dict(dont_sell_when)
|
||||||
|
# if result:
|
||||||
|
# state.ilog(lvl=0,e=f"SELL_PROTECTION {conditions_met} enabled")
|
||||||
|
# return result
|
||||||
147
v2realbot/strategyblocks/activetrade/close/evaluate_close.py
Normal file
147
v2realbot/strategyblocks/activetrade/close/evaluate_close.py
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
from v2realbot.strategyblocks.activetrade.close.close_position import close_position
|
||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.enums.enums import Followup
|
||||||
|
from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus
|
||||||
|
from v2realbot.utils.utils import safe_get
|
||||||
|
from v2realbot.config import KW
|
||||||
|
#from icecream import install, ic
|
||||||
|
from rich import print as printanyway
|
||||||
|
from threading import Event
|
||||||
|
import os
|
||||||
|
from traceback import format_exc
|
||||||
|
from v2realbot.strategyblocks.activetrade.close.conditions import dontexit_protection_met, exit_conditions_met
|
||||||
|
from v2realbot.strategyblocks.activetrade.helpers import get_max_profit_price, get_profit_target_price, get_override_for_active_trade, keyword_conditions_met
|
||||||
|
|
||||||
|
def eval_close_position(state: StrategyState, data):
|
||||||
|
curr_price = float(data['close'])
|
||||||
|
state.ilog(lvl=0,e="Eval CLOSE", price=curr_price, pos=state.positions, avgp=state.avgp, pending=state.vars.pending, activeTrade=str(state.vars.activeTrade))
|
||||||
|
|
||||||
|
if int(state.positions) != 0 and float(state.avgp)>0 and state.vars.pending is None:
|
||||||
|
|
||||||
|
#close position handling
|
||||||
|
#TBD pridat OPTIMALIZACI POZICE - EXIT 1/2
|
||||||
|
|
||||||
|
#mame short pozice - (IDEA: rozlisovat na zaklade aktivniho tradu - umozni mi spoustet i pri soucasne long pozicemi)
|
||||||
|
if int(state.positions) < 0:
|
||||||
|
#get TARGET PRICE pro dany smer a signal
|
||||||
|
goal_price = get_profit_target_price(state, data, TradeDirection.SHORT)
|
||||||
|
max_price = get_max_profit_price(state, data, TradeDirection.SHORT)
|
||||||
|
state.ilog(lvl=1,e=f"Goal price {str(TradeDirection.SHORT)} {goal_price} max price {max_price}")
|
||||||
|
|
||||||
|
|
||||||
|
#EOD EXIT - TBD
|
||||||
|
#FORCED EXIT PRI KONCI DNE
|
||||||
|
|
||||||
|
#SL - execution
|
||||||
|
if curr_price > state.vars.activeTrade.stoploss_value:
|
||||||
|
|
||||||
|
directive_name = 'reverse_for_SL_exit_short'
|
||||||
|
reverse_for_SL_exit = get_override_for_active_trade(state=state, directive_name=directive_name, default_value=safe_get(state.vars, directive_name, "no"))
|
||||||
|
|
||||||
|
if reverse_for_SL_exit == "always":
|
||||||
|
followup_action = Followup.REVERSE
|
||||||
|
elif reverse_for_SL_exit == "cond":
|
||||||
|
followup_action = Followup.REVERSE if keyword_conditions_met(state, data, direction=TradeDirection.SHORT, keyword=KW.slreverseonly, skip_conf_validation=True) else None
|
||||||
|
else:
|
||||||
|
followup_action = None
|
||||||
|
close_position(state=state, data=data, direction=TradeDirection.SHORT, reason="SL REACHED", followup=followup_action)
|
||||||
|
return
|
||||||
|
|
||||||
|
#REVERSE BASED ON REVERSE CONDITIONS
|
||||||
|
if keyword_conditions_met(state, data, direction=TradeDirection.SHORT, keyword=KW.reverse):
|
||||||
|
close_position(state=state, data=data, direction=TradeDirection.SHORT, reason="REVERSE COND MET", followup=Followup.REVERSE)
|
||||||
|
return
|
||||||
|
|
||||||
|
#EXIT ADD CONDITIONS MET (exit and add)
|
||||||
|
if keyword_conditions_met(state, data, direction=TradeDirection.SHORT, keyword=KW.exitadd):
|
||||||
|
close_position(state=state, data=data, direction=TradeDirection.SHORT, reason="EXITADD COND MET", followup=Followup.ADD)
|
||||||
|
return
|
||||||
|
|
||||||
|
#CLOSING BASED ON EXIT CONDITIONS
|
||||||
|
if exit_conditions_met(state, data, TradeDirection.SHORT):
|
||||||
|
directive_name = 'reverse_for_cond_exit_short'
|
||||||
|
reverse_for_cond_exit_short = get_override_for_active_trade(state=state, directive_name=directive_name, default_value=safe_get(state.vars, directive_name, False))
|
||||||
|
directive_name = 'add_for_cond_exit_short'
|
||||||
|
add_for_cond_exit_short = get_override_for_active_trade(state=state, directive_name=directive_name, default_value=safe_get(state.vars, directive_name, False))
|
||||||
|
if reverse_for_cond_exit_short:
|
||||||
|
followup_action = Followup.REVERSE
|
||||||
|
elif add_for_cond_exit_short:
|
||||||
|
followup_action = Followup.ADD
|
||||||
|
else:
|
||||||
|
followup_action = None
|
||||||
|
close_position(state=state, data=data, direction=TradeDirection.SHORT, reason="EXIT COND MET", followup=followup_action)
|
||||||
|
return
|
||||||
|
|
||||||
|
#PROFIT
|
||||||
|
if curr_price<=goal_price:
|
||||||
|
#TODO cekat az slope prestane intenzivn erust, necekat az na klesani
|
||||||
|
#TODO mozna cekat na nejaky signal RSI
|
||||||
|
#TODO pripadne pokud dosahne TGTBB prodat ihned
|
||||||
|
max_price_signal = curr_price<=max_price
|
||||||
|
#OPTIMALIZACE pri stoupajícím angle
|
||||||
|
if max_price_signal or dontexit_protection_met(state=state, data=data,direction=TradeDirection.SHORT) is False:
|
||||||
|
close_position(state=state, data=data, direction=TradeDirection.SHORT, reason=f"PROFIT or MAXPROFIT REACHED {max_price_signal=}")
|
||||||
|
return
|
||||||
|
#mame long
|
||||||
|
elif int(state.positions) > 0:
|
||||||
|
|
||||||
|
#get TARGET PRICE pro dany smer a signal
|
||||||
|
goal_price = get_profit_target_price(state, data, TradeDirection.LONG)
|
||||||
|
max_price = get_max_profit_price(state, data, TradeDirection.LONG)
|
||||||
|
state.ilog(lvl=1,e=f"Goal price {str(TradeDirection.LONG)} {goal_price} max price {max_price}")
|
||||||
|
|
||||||
|
#EOD EXIT - TBD
|
||||||
|
|
||||||
|
#SL - execution
|
||||||
|
if curr_price < state.vars.activeTrade.stoploss_value:
|
||||||
|
directive_name = 'reverse_for_SL_exit_long'
|
||||||
|
reverse_for_SL_exit = get_override_for_active_trade(state, directive_name=directive_name, default_value=safe_get(state.vars, directive_name, "no"))
|
||||||
|
|
||||||
|
state.ilog(lvl=1, e=f"reverse_for_SL_exit {reverse_for_SL_exit}")
|
||||||
|
|
||||||
|
if reverse_for_SL_exit == "always":
|
||||||
|
followup_action = Followup.REVERSE
|
||||||
|
elif reverse_for_SL_exit == "cond":
|
||||||
|
followup_action = Followup.REVERSE if keyword_conditions_met(state, data, direction=TradeDirection.LONG, keyword=KW.slreverseonly, skip_conf_validation=True) else None
|
||||||
|
else:
|
||||||
|
followup_action = None
|
||||||
|
|
||||||
|
close_position(state=state, data=data, direction=TradeDirection.LONG, reason="SL REACHED", followup=followup_action)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
#REVERSE BASED ON REVERSE CONDITIONS
|
||||||
|
if keyword_conditions_met(state, data,TradeDirection.LONG, KW.reverse):
|
||||||
|
close_position(state=state, data=data, direction=TradeDirection.LONG, reason="REVERSE COND MET", followup=Followup.REVERSE)
|
||||||
|
return
|
||||||
|
|
||||||
|
#EXIT ADD CONDITIONS MET (exit and add)
|
||||||
|
if keyword_conditions_met(state, data, TradeDirection.LONG, KW.exitadd):
|
||||||
|
close_position(state=state, data=data, direction=TradeDirection.LONG, reason="EXITADD COND MET", followup=Followup.ADD)
|
||||||
|
return
|
||||||
|
|
||||||
|
#EXIT CONDITIONS
|
||||||
|
if exit_conditions_met(state, data, TradeDirection.LONG):
|
||||||
|
directive_name = 'reverse_for_cond_exit_long'
|
||||||
|
reverse_for_cond_exit_long = get_override_for_active_trade(state, directive_name=directive_name, default_value=safe_get(state.vars, directive_name, False))
|
||||||
|
directive_name = 'add_for_cond_exit_long'
|
||||||
|
add_for_cond_exit_long = get_override_for_active_trade(state, directive_name=directive_name, default_value=safe_get(state.vars, directive_name, False))
|
||||||
|
if reverse_for_cond_exit_long:
|
||||||
|
followup_action = Followup.REVERSE
|
||||||
|
elif add_for_cond_exit_long:
|
||||||
|
followup_action = Followup.ADD
|
||||||
|
else:
|
||||||
|
followup_action = None
|
||||||
|
close_position(state=state, data=data, direction=TradeDirection.LONG, reason="EXIT CONDS MET", followup=followup_action)
|
||||||
|
return
|
||||||
|
|
||||||
|
#PROFIT
|
||||||
|
if curr_price>=goal_price:
|
||||||
|
#TODO cekat az slope prestane intenzivn erust, necekat az na klesani
|
||||||
|
#TODO mozna cekat na nejaky signal RSI
|
||||||
|
#TODO pripadne pokud dosahne TGTBB prodat ihned
|
||||||
|
max_price_signal = curr_price>=max_price
|
||||||
|
#OPTIMALIZACE pri stoupajícím angle
|
||||||
|
if max_price_signal or dontexit_protection_met(state, data, direction=TradeDirection.LONG) is False:
|
||||||
|
close_position(state=state, data=data, direction=TradeDirection.LONG, reason=f"PROFIT or MAXPROFIT REACHED {max_price_signal=}")
|
||||||
|
return
|
||||||
186
v2realbot/strategyblocks/activetrade/helpers.py
Normal file
186
v2realbot/strategyblocks/activetrade/helpers.py
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.strategy.StrategyOrderLimitVykladaciNormalizedMYSELL import StrategyOrderLimitVykladaciNormalizedMYSELL
|
||||||
|
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, Followup
|
||||||
|
from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus
|
||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.utils.directive_utils import get_conditions_from_configuration
|
||||||
|
from v2realbot.ml.mlutils import load_model
|
||||||
|
from v2realbot.common.model import SLHistory
|
||||||
|
from v2realbot.config import KW
|
||||||
|
from uuid import uuid4
|
||||||
|
from datetime import datetime
|
||||||
|
#import random
|
||||||
|
import json
|
||||||
|
import numpy as np
|
||||||
|
#from icecream import install, ic
|
||||||
|
from rich import print as printanyway
|
||||||
|
from threading import Event
|
||||||
|
import os
|
||||||
|
from traceback import format_exc
|
||||||
|
from v2realbot.strategyblocks.helpers import normalize_tick
|
||||||
|
from v2realbot.strategyblocks.indicators.helpers import evaluate_directive_conditions
|
||||||
|
|
||||||
|
#otestuje keyword podminky (napr. reverse_if, nebo exitadd_if)
|
||||||
|
def keyword_conditions_met(state, data, direction: TradeDirection, keyword: KW, skip_conf_validation: bool = False):
|
||||||
|
action = str(keyword).upper()
|
||||||
|
if direction == TradeDirection.LONG:
|
||||||
|
smer = "long"
|
||||||
|
else:
|
||||||
|
smer = "short"
|
||||||
|
|
||||||
|
if skip_conf_validation is False:
|
||||||
|
directive_name = "exit_cond_only_on_confirmed"
|
||||||
|
exit_cond_only_on_confirmed = get_override_for_active_trade(state, directive_name=directive_name, default_value=safe_get(state.vars, directive_name, False))
|
||||||
|
|
||||||
|
if exit_cond_only_on_confirmed and data['confirmed'] == 0:
|
||||||
|
state.ilog(lvl=0,e=f"{action} CHECK COND ONLY ON CONFIRMED BAR")
|
||||||
|
return False
|
||||||
|
|
||||||
|
#TOTO zatim u REVERSU neresime
|
||||||
|
# #POKUD je nastaven MIN PROFIT, zkontrolujeme ho a az pripadne pustime CONDITIONY
|
||||||
|
# directive_name = "exit_cond_min_profit"
|
||||||
|
# exit_cond_min_profit = get_override_for_active_trade(directive_name=directive_name, default_value=safe_get(state.vars, directive_name, None))
|
||||||
|
|
||||||
|
# #máme nastavený exit_cond_min_profit
|
||||||
|
# # zjistíme, zda jsme v daném profit a případně nepustíme dál
|
||||||
|
# # , zjistíme aktuální cenu a přičteme k avgp tento profit a podle toho pustime dal
|
||||||
|
|
||||||
|
# if exit_cond_min_profit is not None:
|
||||||
|
# exit_cond_min_profit_normalized = normalize_tick(float(exit_cond_min_profit))
|
||||||
|
# exit_cond_goal_price = price2dec(float(state.avgp)+exit_cond_min_profit_normalized,3) if int(state.positions) > 0 else price2dec(float(state.avgp)-exit_cond_min_profit_normalized,3)
|
||||||
|
# curr_price = float(data["close"])
|
||||||
|
# state.ilog(lvl=0,e=f"EXIT COND min profit {exit_cond_goal_price=} {exit_cond_min_profit=} {exit_cond_min_profit_normalized=} {curr_price=}")
|
||||||
|
# if (int(state.positions) < 0 and curr_price<=exit_cond_goal_price) or (int(state.positions) > 0 and curr_price>=exit_cond_goal_price):
|
||||||
|
# state.ilog(lvl=0,e=f"EXIT COND min profit PASS - POKRACUJEME")
|
||||||
|
# else:
|
||||||
|
# state.ilog(lvl=0,e=f"EXIT COND min profit NOT PASS")
|
||||||
|
# return False
|
||||||
|
|
||||||
|
#TOTO ZATIM NEMA VYZNAM
|
||||||
|
# options = safe_get(state.vars, 'exit_conditions', None)
|
||||||
|
# if options is None:
|
||||||
|
# state.ilog(lvl=0,e="No options for exit conditions in stratvars")
|
||||||
|
# return False
|
||||||
|
|
||||||
|
# disable_exit_proteciton_when = dict(AND=dict(), OR=dict())
|
||||||
|
|
||||||
|
# #preconditions
|
||||||
|
# disable_exit_proteciton_when['disabled_in_config'] = safe_get(options, 'enabled', False) is False
|
||||||
|
# #too good to be true (maximum profit)
|
||||||
|
# #disable_sell_proteciton_when['tgtbt_reached'] = safe_get(options, 'tgtbt', False) is False
|
||||||
|
# disable_exit_proteciton_when['disable_if_positions_above'] = int(safe_get(options, 'disable_if_positions_above', 0)) < abs(int(state.positions))
|
||||||
|
|
||||||
|
# #testing preconditions
|
||||||
|
# result, conditions_met = eval_cond_dict(disable_exit_proteciton_when)
|
||||||
|
# if result:
|
||||||
|
# state.ilog(lvl=0,e=f"EXIT_CONDITION for{smer} DISABLED by {conditions_met}", **conditions_met)
|
||||||
|
# return False
|
||||||
|
|
||||||
|
#bereme bud exit condition signalu, ktery activeTrade vygeneroval+ fallback na general
|
||||||
|
state.ilog(lvl=0,e=f"{action} CONDITIONS ENTRY {smer}", conditions=state.vars.conditions[KW.reverse])
|
||||||
|
|
||||||
|
mother_signal = state.vars.activeTrade.generated_by
|
||||||
|
|
||||||
|
if mother_signal is not None:
|
||||||
|
cond_dict = state.vars.conditions[keyword][mother_signal][smer]
|
||||||
|
result, conditions_met = evaluate_directive_conditions(state, cond_dict, "OR")
|
||||||
|
state.ilog(lvl=1,e=f"{action} CONDITIONS of {mother_signal} =OR= {result}", **conditions_met, cond_dict=cond_dict)
|
||||||
|
if result:
|
||||||
|
return True
|
||||||
|
|
||||||
|
#OR neprosly testujeme AND
|
||||||
|
result, conditions_met = evaluate_directive_conditions(state, cond_dict, "AND")
|
||||||
|
state.ilog(lvl=1,e=f"{action} CONDITIONS of {mother_signal} =AND= {result}", **conditions_met, cond_dict=cond_dict)
|
||||||
|
if result:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
#pokud nemame mother signal nebo exit nevratil nic, fallback na common
|
||||||
|
cond_dict = state.vars.conditions[keyword]["common"][smer]
|
||||||
|
result, conditions_met = evaluate_directive_conditions(state, cond_dict, "OR")
|
||||||
|
state.ilog(lvl=1,e=f"{action} CONDITIONS of COMMON =OR= {result}", **conditions_met, cond_dict=cond_dict)
|
||||||
|
if result:
|
||||||
|
return True
|
||||||
|
|
||||||
|
#OR neprosly testujeme AND
|
||||||
|
result, conditions_met = evaluate_directive_conditions(state, cond_dict, "AND")
|
||||||
|
state.ilog(lvl=0,e=f"{action} CONDITIONS of COMMON =AND= {result}", **conditions_met, cond_dict=cond_dict)
|
||||||
|
if result:
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
#mozna do SL helpers tuto
|
||||||
|
def insert_SL_history(state):
|
||||||
|
#insert stoploss history as key sl_history into runner archive extended data
|
||||||
|
state.extData["sl_history"].append(SLHistory(id=state.vars.activeTrade.id, time=state.time, sl_val=state.vars.activeTrade.stoploss_value))
|
||||||
|
|
||||||
|
|
||||||
|
def get_default_sl_value(state, direction: TradeDirection):
|
||||||
|
|
||||||
|
if direction == TradeDirection.LONG:
|
||||||
|
smer = "long"
|
||||||
|
else:
|
||||||
|
smer = "short"
|
||||||
|
|
||||||
|
#TODO zda signal, ktery activeTrade vygeneroval, nema vlastni nastaveni + fallback na general
|
||||||
|
|
||||||
|
options = safe_get(state.vars, 'exit', None)
|
||||||
|
|
||||||
|
if options is None:
|
||||||
|
state.ilog(lvl=1,e="No options for exit in stratvars. Fallback.")
|
||||||
|
return 0.01
|
||||||
|
directive_name = 'SL_defval_'+str(smer)
|
||||||
|
val = get_override_for_active_trade(state, directive_name=directive_name, default_value=safe_get(options, directive_name, 0.01))
|
||||||
|
return val
|
||||||
|
#funkce pro direktivy, ktere muzou byt overridnute v signal sekci
|
||||||
|
#tato funkce vyhleda signal sekci aktivniho tradu a pokusi se danou direktivu vyhledat tam,
|
||||||
|
#pokud nenajde tak vrati default, ktery byl poskytnut
|
||||||
|
def get_override_for_active_trade(state, directive_name: str, default_value: str):
|
||||||
|
val = default_value
|
||||||
|
override = "NO"
|
||||||
|
mother_signal = state.vars.activeTrade.generated_by
|
||||||
|
|
||||||
|
if mother_signal is not None:
|
||||||
|
override = "YES "+mother_signal
|
||||||
|
val = safe_get(state.vars.signals[mother_signal], directive_name, default_value)
|
||||||
|
|
||||||
|
state.ilog(lvl=0,e=f"{directive_name} OVERRIDE {override} NEWVAL:{val} ORIGINAL:{default_value} {mother_signal}", mother_signal=mother_signal,default_value=default_value)
|
||||||
|
return val
|
||||||
|
|
||||||
|
def get_profit_target_price(state, data, direction: TradeDirection):
|
||||||
|
if direction == TradeDirection.LONG:
|
||||||
|
smer = "long"
|
||||||
|
else:
|
||||||
|
smer = "short"
|
||||||
|
|
||||||
|
directive_name = "profit"
|
||||||
|
def_profit_both_directions = get_override_for_active_trade(state, directive_name=directive_name, default_value=safe_get(state.vars, directive_name, 0.50))
|
||||||
|
|
||||||
|
#profit pro dany smer
|
||||||
|
directive_name = 'profit_'+str(smer)
|
||||||
|
def_profit = get_override_for_active_trade(state, directive_name=directive_name, default_value=def_profit_both_directions)
|
||||||
|
|
||||||
|
normalized_def_profit = normalize_tick(state, data, float(def_profit))
|
||||||
|
|
||||||
|
state.ilog(lvl=0,e=f"PROFIT {def_profit=} {normalized_def_profit=}")
|
||||||
|
|
||||||
|
return price2dec(float(state.avgp)+normalized_def_profit,3) if int(state.positions) > 0 else price2dec(float(state.avgp)-normalized_def_profit,3)
|
||||||
|
|
||||||
|
def get_max_profit_price(state, data, direction: TradeDirection):
|
||||||
|
if direction == TradeDirection.LONG:
|
||||||
|
smer = "long"
|
||||||
|
else:
|
||||||
|
smer = "short"
|
||||||
|
|
||||||
|
directive_name = "max_profit"
|
||||||
|
max_profit_both_directions = get_override_for_active_trade(state, directive_name=directive_name, default_value=safe_get(state.vars, directive_name, 0.35))
|
||||||
|
|
||||||
|
#max profit pro dany smer, s fallbackem na bez smeru
|
||||||
|
directive_name = 'max_profit_'+str(smer)
|
||||||
|
max_profit = get_override_for_active_trade(state, directive_name=directive_name, default_value=max_profit_both_directions)
|
||||||
|
|
||||||
|
normalized_max_profit = normalize_tick(state,data,float(max_profit))
|
||||||
|
|
||||||
|
state.ilog(lvl=0,e=f"MAX PROFIT {max_profit=} {normalized_max_profit=}")
|
||||||
|
|
||||||
|
return price2dec(float(state.avgp)+normalized_max_profit,3) if int(state.positions) > 0 else price2dec(float(state.avgp)-normalized_max_profit,3)
|
||||||
89
v2realbot/strategyblocks/activetrade/sl/trailsl.py
Normal file
89
v2realbot/strategyblocks/activetrade/sl/trailsl.py
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus
|
||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get
|
||||||
|
#from icecream import install, ic
|
||||||
|
from rich import print as printanyway
|
||||||
|
from threading import Event
|
||||||
|
import os
|
||||||
|
from traceback import format_exc
|
||||||
|
from v2realbot.strategyblocks.activetrade.helpers import get_override_for_active_trade, normalize_tick, insert_SL_history
|
||||||
|
|
||||||
|
|
||||||
|
#pokud se cena posouva nasim smerem olespon o (0.05) nad (SL + 0.09val), posuneme SL o offset
|
||||||
|
#+ varianta - skoncit breakeven
|
||||||
|
|
||||||
|
#DIREKTIVY:
|
||||||
|
#maximalni stoploss, fallout pro "exit_short_if" direktivy
|
||||||
|
# SL_defval_short = 0.10
|
||||||
|
# SL_defval_long = 0.10
|
||||||
|
# SL_trailing_enabled_short = true
|
||||||
|
# SL_trailing_enabled_long = true
|
||||||
|
# #minimalni vzdalenost od aktualni SL, aby se SL posunula na
|
||||||
|
# SL_trailing_offset_short = 0.05
|
||||||
|
# SL_trailing_offset_long = 0.05
|
||||||
|
# #zda trailing zastavit na brakeeven
|
||||||
|
# SL_trailing_stop_at_breakeven_short = true
|
||||||
|
# SL_trailing_stop_at_breakeven_long = true
|
||||||
|
|
||||||
|
def trail_SL_management(state: StrategyState, data):
|
||||||
|
if int(state.positions) != 0 and float(state.avgp)>0 and state.vars.pending is None:
|
||||||
|
|
||||||
|
if int(state.positions) < 0:
|
||||||
|
direction = TradeDirection.SHORT
|
||||||
|
smer = "short"
|
||||||
|
else:
|
||||||
|
direction = TradeDirection.LONG
|
||||||
|
smer = "long"
|
||||||
|
|
||||||
|
# zatim nastaveni SL plati pro vsechny - do budoucna per signal - pridat sekci
|
||||||
|
|
||||||
|
options = safe_get(state.vars, 'exit', None)
|
||||||
|
if options is None:
|
||||||
|
state.ilog(lvl=1,e="Trail SL. No options for exit conditions in stratvars.")
|
||||||
|
return
|
||||||
|
|
||||||
|
directive_name = 'SL_trailing_enabled_'+str(smer)
|
||||||
|
sl_trailing_enabled = get_override_for_active_trade(state=state, directive_name=directive_name, default_value=safe_get(options, directive_name, False))
|
||||||
|
|
||||||
|
|
||||||
|
#SL_trailing_protection_window_short
|
||||||
|
directive_name = 'SL_trailing_protection_window_'+str(smer)
|
||||||
|
SL_trailing_protection_window = get_override_for_active_trade(state=state, directive_name=directive_name, default_value=safe_get(options, directive_name, 0))
|
||||||
|
index_to_compare = int(state.vars.last_in_index)+int(SL_trailing_protection_window)
|
||||||
|
if index_to_compare > int(data["index"]):
|
||||||
|
state.ilog(lvl=1,e=f"SL trail PROTECTION WINDOW {SL_trailing_protection_window} - TOO SOON", currindex=data["index"], index_to_compare=index_to_compare, last_in_index=state.vars.last_in_index)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if sl_trailing_enabled is True:
|
||||||
|
directive_name = 'SL_trailing_stop_at_breakeven_'+str(smer)
|
||||||
|
stop_breakeven = get_override_for_active_trade(state=state, directive_name=directive_name, default_value=safe_get(options, directive_name, False))
|
||||||
|
directive_name = 'SL_defval_'+str(smer)
|
||||||
|
def_SL = get_override_for_active_trade(state=state, directive_name=directive_name, default_value=safe_get(options, directive_name, 0.01))
|
||||||
|
directive_name = "SL_trailing_offset_"+str(smer)
|
||||||
|
offset = get_override_for_active_trade(state=state, directive_name=directive_name, default_value=safe_get(options, directive_name, 0.01))
|
||||||
|
|
||||||
|
#pokud je pozadovan trail jen do breakeven a uz prekroceno
|
||||||
|
if (direction == TradeDirection.LONG and stop_breakeven and state.vars.activeTrade.stoploss_value >= float(state.avgp)) or (direction == TradeDirection.SHORT and stop_breakeven and state.vars.activeTrade.stoploss_value <= float(state.avgp)):
|
||||||
|
state.ilog(lvl=1,e=f"SL trail STOP at breakeven {str(smer)} SL:{state.vars.activeTrade.stoploss_value} UNCHANGED", stop_breakeven=stop_breakeven)
|
||||||
|
return
|
||||||
|
|
||||||
|
#IDEA: Nyni posouvame SL o offset, mozna ji posunout jen o direktivu step ?
|
||||||
|
|
||||||
|
offset_normalized = normalize_tick(state, data, offset) #to ticks and from options
|
||||||
|
def_SL_normalized = normalize_tick(state, data, def_SL)
|
||||||
|
if direction == TradeDirection.LONG:
|
||||||
|
move_SL_threshold = state.vars.activeTrade.stoploss_value + offset_normalized + def_SL_normalized
|
||||||
|
state.ilog(lvl=1,e=f"SL TRAIL EVAL {smer} SL:{round(state.vars.activeTrade.stoploss_value,3)} TRAILGOAL:{move_SL_threshold}", def_SL=def_SL, offset=offset, offset_normalized=offset_normalized, def_SL_normalized=def_SL_normalized)
|
||||||
|
if (move_SL_threshold) < data['close']:
|
||||||
|
state.vars.activeTrade.stoploss_value += offset_normalized
|
||||||
|
insert_SL_history(state)
|
||||||
|
state.ilog(lvl=1,e=f"SL TRAIL TH {smer} reached {move_SL_threshold} SL moved to {state.vars.activeTrade.stoploss_value}", offset_normalized=offset_normalized, def_SL_normalized=def_SL_normalized)
|
||||||
|
elif direction == TradeDirection.SHORT:
|
||||||
|
move_SL_threshold = state.vars.activeTrade.stoploss_value - offset_normalized - def_SL_normalized
|
||||||
|
state.ilog(lvl=0,e=f"SL TRAIL EVAL {smer} SL:{round(state.vars.activeTrade.stoploss_value,3)} TRAILGOAL:{move_SL_threshold}", def_SL=def_SL, offset=offset, offset_normalized=offset_normalized, def_SL_normalized=def_SL_normalized)
|
||||||
|
if (move_SL_threshold) > data['close']:
|
||||||
|
state.vars.activeTrade.stoploss_value -= offset_normalized
|
||||||
|
insert_SL_history(state)
|
||||||
|
state.ilog(lvl=1,e=f"SL TRAIL GOAL {smer} reached {move_SL_threshold} SL moved to {state.vars.activeTrade.stoploss_value}", offset_normalized=offset_normalized, def_SL_normalized=def_SL_normalized)
|
||||||
47
v2realbot/strategyblocks/helpers.py
Normal file
47
v2realbot/strategyblocks/helpers.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.strategy.StrategyOrderLimitVykladaciNormalizedMYSELL import StrategyOrderLimitVykladaciNormalizedMYSELL
|
||||||
|
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, Followup
|
||||||
|
from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus
|
||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.utils.directive_utils import get_conditions_from_configuration
|
||||||
|
from v2realbot.ml.mlutils import load_model
|
||||||
|
from v2realbot.common.model import SLHistory
|
||||||
|
from v2realbot.config import KW
|
||||||
|
from uuid import uuid4
|
||||||
|
from datetime import datetime
|
||||||
|
#import random
|
||||||
|
#from icecream import install, ic
|
||||||
|
from rich import print as printanyway
|
||||||
|
from threading import Event
|
||||||
|
import os
|
||||||
|
from traceback import format_exc
|
||||||
|
|
||||||
|
def normalize_tick(state, data, tick: float, price: float = None, return_two_decimals: bool = False):
|
||||||
|
"""
|
||||||
|
Pokud je nastaveno v direktive:
|
||||||
|
#zda normalizovat vsechyn ticky (tzn. profit, maxprofit, SL atp.)
|
||||||
|
Normalize_ticks= true
|
||||||
|
Normalized Tick base price = 30
|
||||||
|
|
||||||
|
prevede normalizovany tick na tick odpovidajici vstupni cene
|
||||||
|
vysledek je zaokoruhleny na 2 des.mista
|
||||||
|
|
||||||
|
u cen pod 30, vrací 0.01. U cen nad 30 vrací pomerne zvetsene,
|
||||||
|
|
||||||
|
"""
|
||||||
|
#nemusime dodavat cenu, bereme aktualni
|
||||||
|
if price is None:
|
||||||
|
price = data["close"]
|
||||||
|
|
||||||
|
normalize_ticks = safe_get(state.vars, "normalize_ticks",False)
|
||||||
|
normalized_base_price = safe_get(state.vars, "normalized_base_price",30)
|
||||||
|
if normalize_ticks:
|
||||||
|
if price<normalized_base_price:
|
||||||
|
return tick
|
||||||
|
else:
|
||||||
|
#ratio of price vs base price
|
||||||
|
ratio = price/normalized_base_price
|
||||||
|
normalized_tick = ratio*tick
|
||||||
|
return price2dec(normalized_tick) if return_two_decimals else normalized_tick
|
||||||
|
else:
|
||||||
|
return tick
|
||||||
49
v2realbot/strategyblocks/indicators/RSI.py
Normal file
49
v2realbot/strategyblocks/indicators/RSI.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.indicators.indicators import ema, natr, roc
|
||||||
|
from v2realbot.indicators.oscillators import rsi
|
||||||
|
from traceback import format_exc
|
||||||
|
#RSI INDICATOR
|
||||||
|
# type = RSI, source = [close, vwap, hlcc4], rsi_length = [14], MA_length = int (optional), on_confirmed_only = [true, false]
|
||||||
|
# pokud existuje MA, vytvarime i stejnojnojmenny MAcko
|
||||||
|
def populate_dynamic_RSI_indicator(data, state: StrategyState, name):
|
||||||
|
ind_type = "RSI"
|
||||||
|
options = safe_get(state.vars.indicators, name, None)
|
||||||
|
if options is None:
|
||||||
|
state.ilog(lvl=1,e=f"No options for {name} in stratvars")
|
||||||
|
return
|
||||||
|
|
||||||
|
if safe_get(options, "type", False) is False or safe_get(options, "type", False) != ind_type:
|
||||||
|
state.ilog(lvl=1,e="Type error")
|
||||||
|
return
|
||||||
|
|
||||||
|
#poustet kazdy tick nebo jenom na confirmed baru (on_confirmed_only = true)
|
||||||
|
on_confirmed_only = safe_get(options, 'on_confirmed_only', False)
|
||||||
|
req_source = safe_get(options, 'source', 'vwap')
|
||||||
|
if req_source not in ["close", "vwap","hlcc4"]:
|
||||||
|
state.ilog(lvl=1,e=f"Unknown source error {req_source} for {name}")
|
||||||
|
return
|
||||||
|
rsi_length = int(safe_get(options, "RSI_length",14))
|
||||||
|
rsi_MA_length = safe_get(options, "MA_length", None)
|
||||||
|
|
||||||
|
if on_confirmed_only is False or (on_confirmed_only is True and data['confirmed']==1):
|
||||||
|
try:
|
||||||
|
source = state.bars[req_source]
|
||||||
|
#cekame na dostatek dat
|
||||||
|
if len(source) > rsi_length:
|
||||||
|
rsi_res = rsi(source, rsi_length)
|
||||||
|
rsi_value = round(rsi_res[-1],4)
|
||||||
|
state.indicators[name][-1]=rsi_value
|
||||||
|
state.ilog(lvl=0,e=f"IND {name} RSI {rsi_value}")
|
||||||
|
|
||||||
|
if rsi_MA_length is not None:
|
||||||
|
src = state.indicators[name][-rsi_MA_length:]
|
||||||
|
rsi_MA_res = ema(src, rsi_MA_length)
|
||||||
|
rsi_MA_value = round(rsi_MA_res[-1],4)
|
||||||
|
state.indicators[name+"MA"][-1]=rsi_MA_value
|
||||||
|
state.ilog(lvl=0,e=f"IND {name} RSIMA {rsi_MA_value}")
|
||||||
|
|
||||||
|
else:
|
||||||
|
state.ilog(lvl=0,e=f"IND {name} RSI necháváme 0", message="not enough source data", source=source, rsi_length=rsi_length)
|
||||||
|
except Exception as e:
|
||||||
|
state.ilog(lvl=1,e=f"IND ERROR {name} RSI necháváme 0", message=str(e)+format_exc())
|
||||||
33
v2realbot/strategyblocks/indicators/atr.py
Normal file
33
v2realbot/strategyblocks/indicators/atr.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
from v2realbot.indicators.indicators import ema, atr, roc
|
||||||
|
from v2realbot.indicators.oscillators import rsi
|
||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from traceback import format_exc
|
||||||
|
|
||||||
|
#TODO ATR INDICATOR - predelat na CUSTOM a udelat scitani a odecteni od close (atru, atrd)
|
||||||
|
# type = ATR, ĺength = [14], on_confirmed_only = [true, false]
|
||||||
|
def populate_dynamic_atr_indicator(data, state: StrategyState, name):
|
||||||
|
ind_type = "ATR"
|
||||||
|
options = safe_get(state.vars.indicators, name, None)
|
||||||
|
if options is None:
|
||||||
|
state.ilog(lvl=1,e=f"No options for {name} in stratvars")
|
||||||
|
return
|
||||||
|
|
||||||
|
#poustet kazdy tick nebo jenom na confirmed baru (on_confirmed_only = true)
|
||||||
|
on_confirmed_only = safe_get(options, 'on_confirmed_only', False)
|
||||||
|
atr_length = int(safe_get(options, "length",5))
|
||||||
|
if on_confirmed_only is False or (on_confirmed_only is True and data['confirmed']==1):
|
||||||
|
try:
|
||||||
|
source_high = state.bars["high"][-atr_length:]
|
||||||
|
source_low = state.bars["low"][-atr_length:]
|
||||||
|
source_close = state.bars["close"][-atr_length:]
|
||||||
|
#if len(source) > ema_length:
|
||||||
|
atr_value = atr(source_high, source_low, source_close, atr_length)
|
||||||
|
val = round(atr_value[-1],4)
|
||||||
|
state.indicators[name][-1]= val
|
||||||
|
#state.indicators[name][-1]= round2five(val)
|
||||||
|
state.ilog(lvl=0,e=f"IND {name} ATR {val} {atr_length=}")
|
||||||
|
#else:
|
||||||
|
# state.ilog(lvl=0,e=f"IND {name} EMA necháváme 0", message="not enough source data", source=source, ema_length=ema_length)
|
||||||
|
except Exception as e:
|
||||||
|
state.ilog(lvl=0,e=f"IND ERROR {name} ATR necháváme 0", message=str(e)+format_exc())
|
||||||
23
v2realbot/strategyblocks/indicators/cbar_price.py
Normal file
23
v2realbot/strategyblocks/indicators/cbar_price.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
|
||||||
|
def populate_cbar_tick_price_indicator(data, state: StrategyState):
|
||||||
|
try:
|
||||||
|
#pokud v potvrzovacím baru nebyly zmeny, nechavam puvodni hodnoty
|
||||||
|
# if tick_delta_volume == 0:
|
||||||
|
# state.indicators.tick_price[-1] = state.indicators.tick_price[-2]
|
||||||
|
# state.indicators.tick_volume[-1] = state.indicators.tick_volume[-2]
|
||||||
|
# else:
|
||||||
|
|
||||||
|
#tick_price = round2five(data['close'])
|
||||||
|
tick_price = data['close']
|
||||||
|
tick_delta_volume = data['volume'] - state.vars.last_tick_volume
|
||||||
|
|
||||||
|
state.cbar_indicators.tick_price[-1] = tick_price
|
||||||
|
state.cbar_indicators.tick_volume[-1] = tick_delta_volume
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
state.ilog(lvl=0,e=f"TICK PRICE {tick_price} VOLUME {tick_delta_volume} {data['confirmed']=}", prev_price=state.vars.last_tick_price, prev_volume=state.vars.last_tick_volume)
|
||||||
|
|
||||||
|
state.vars.last_tick_price = tick_price
|
||||||
|
state.vars.last_tick_volume = data['volume']
|
||||||
27
v2realbot/strategyblocks/indicators/cbar_rsi.py
Normal file
27
v2realbot/strategyblocks/indicators/cbar_rsi.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.indicators.indicators import ema, natr, roc
|
||||||
|
from v2realbot.indicators.oscillators import rsi
|
||||||
|
from traceback import format_exc
|
||||||
|
|
||||||
|
#WIP
|
||||||
|
def populate_cbar_rsi_indicator(data, state):
|
||||||
|
#CBAR RSI indicator
|
||||||
|
options = safe_get(state.vars.indicators, 'crsi', None)
|
||||||
|
if options is None:
|
||||||
|
state.ilog(lvl=1,e="No options for crsi in stratvars")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
crsi_length = int(safe_get(options, 'crsi_length', 14))
|
||||||
|
source = state.cbar_indicators.tick_price #[-rsi_length:] #state.bars.vwap
|
||||||
|
crsi_res = rsi(source, crsi_length)
|
||||||
|
crsi_value = crsi_res[-1]
|
||||||
|
if str(crsi_value) == "nan":
|
||||||
|
crsi_value = 0
|
||||||
|
state.cbar_indicators.CRSI[-1]=crsi_value
|
||||||
|
#state.ilog(lvl=0,e=f"RSI {rsi_length=} {rsi_value=} {rsi_dont_buy=} {rsi_buy_signal=}", rsi_indicator=state.indicators.RSI14[-5:])
|
||||||
|
except Exception as e:
|
||||||
|
state.ilog(lvl=1,e=f"CRSI {crsi_length=} necháváme 0", message=str(e)+format_exc())
|
||||||
|
#state.indicators.RSI14[-1]=0
|
||||||
1
v2realbot/strategyblocks/indicators/custom/__init__.py
Normal file
1
v2realbot/strategyblocks/indicators/custom/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
from . import *
|
||||||
@ -0,0 +1,72 @@
|
|||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.indicators.indicators import ema, natr, roc
|
||||||
|
from v2realbot.strategyblocks.indicators.helpers import get_source_series
|
||||||
|
from rich import print as printanyway
|
||||||
|
from traceback import format_exc
|
||||||
|
from v2realbot.ml.ml import ModelML
|
||||||
|
import numpy as np
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
#WIP
|
||||||
|
#indicator to run on bar multiples
|
||||||
|
#např. umožní RSI na 5min
|
||||||
|
#params: resolution (bar multiples)
|
||||||
|
def upscaledrsi(state, params):
|
||||||
|
funcName = "upscaledrsi"
|
||||||
|
#new res in seconds
|
||||||
|
new_resolution = safe_get(params, "resolution", None)
|
||||||
|
old_resolution = state.bars["resolution"][-1]
|
||||||
|
|
||||||
|
#pokud potrebuju vsechny bary, tak si je dotahnu
|
||||||
|
new_bars = {}
|
||||||
|
new_bars = create_new_bars(state.bars, new_resolution)
|
||||||
|
#val = rsi(bars.)
|
||||||
|
|
||||||
|
#pokud potrebuju jen close nebo open muzu pouzit toto
|
||||||
|
# vezme to N-th element z pole
|
||||||
|
def resample_close_prices(bars, new_resolution):
|
||||||
|
# Check that the new resolution is a multiple of the old resolution.
|
||||||
|
if new_resolution % bars['resolution'][-1] != 0:
|
||||||
|
raise ValueError('New resolution must be a multiple of the old resolution.')
|
||||||
|
|
||||||
|
# Calculate the step size for selecting every Nth element.
|
||||||
|
step = new_resolution // bars['resolution'][-1]
|
||||||
|
|
||||||
|
# Extract close prices at the new resolution.
|
||||||
|
new_close_prices = bars['close'][::step]
|
||||||
|
#optimizied - but works only for numpy arrays, prevedeni z listu na numpy is costly - bars_array = np.array(bars)
|
||||||
|
#new_close_prices = np.take(bars['close'], np.arange(0, len(bars['close']), step), axis=0)
|
||||||
|
|
||||||
|
return new_close_prices
|
||||||
|
|
||||||
|
|
||||||
|
##TOTO PROJIT
|
||||||
|
#pokud je vstup jedna hodnota - muzu brat close,open v danem rozliseni tzn. jen N-th hodnotu zde
|
||||||
|
# Check that the new resolution is a multiple of the old resolution.
|
||||||
|
if new_resolution % state.bars["resolution"][-1] != 0:
|
||||||
|
raise ValueError('The new resolution must be a multiple of the old resolution.')
|
||||||
|
|
||||||
|
#get the number of bars in the new resolution.
|
||||||
|
n = new_resolution // old_resolution
|
||||||
|
# Calculate the new resolution values.
|
||||||
|
new_resolution_values = old_resolution_values.reshape((-1, new_resolution // len(old_resolution_values)))
|
||||||
|
|
||||||
|
# Select the N-th values from the new resolution values.
|
||||||
|
new_resolution_values[:, n]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
source1 = safe_get(params, "source1", None)
|
||||||
|
if source1 in ["open","high","low","close","vwap","hlcc4"]:
|
||||||
|
source1_series = state.bars[source1]
|
||||||
|
else:
|
||||||
|
source1_series = state.indicators[source1]
|
||||||
|
source2 = safe_get(params, "source2", None)
|
||||||
|
if source2 in ["open","high","low","close","vwap","hlcc4"]:
|
||||||
|
source2_series = state.bars[source2]
|
||||||
|
else:
|
||||||
|
source2_series = state.indicators[source2]
|
||||||
|
mode = safe_get(params, "type")
|
||||||
|
state.ilog(lvl=0,e=f"INSIDE {funcName} {source1=} {source2=} {mode=}", **params)
|
||||||
|
|
||||||
23
v2realbot/strategyblocks/indicators/custom/barparams.py
Normal file
23
v2realbot/strategyblocks/indicators/custom/barparams.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.indicators.indicators import ema, natr, roc
|
||||||
|
from v2realbot.strategyblocks.indicators.helpers import get_source_series
|
||||||
|
from rich import print as printanyway
|
||||||
|
from traceback import format_exc
|
||||||
|
from v2realbot.ml.ml import ModelML
|
||||||
|
import numpy as np
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
#indicator allowing to be based on any bar parameter (index, high,open,close,trades,volume, etc.)
|
||||||
|
def barparams(state, params):
|
||||||
|
funcName = "barparams"
|
||||||
|
if params is None:
|
||||||
|
return -2, "params required"
|
||||||
|
source = safe_get(params, "source", None)
|
||||||
|
if source is None:
|
||||||
|
return -2, "source required"
|
||||||
|
try:
|
||||||
|
return 0, state.bars[source][-1]
|
||||||
|
except Exception as e:
|
||||||
|
return -2, str(e)+format_exc()
|
||||||
42
v2realbot/strategyblocks/indicators/custom/basestats.py
Normal file
42
v2realbot/strategyblocks/indicators/custom/basestats.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.indicators.indicators import ema, natr, roc
|
||||||
|
from v2realbot.strategyblocks.indicators.helpers import get_source_series
|
||||||
|
from rich import print as printanyway
|
||||||
|
from traceback import format_exc
|
||||||
|
from v2realbot.ml.ml import ModelML
|
||||||
|
import numpy as np
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
#vstupem je bud indicator nebo bar parametr
|
||||||
|
#na tomto vstupu dokaze provest zakladni statisticke funkce pro subpole X hodnot zpatky
|
||||||
|
#podporovane functions: min, max, mean
|
||||||
|
def basestats(state, params):
|
||||||
|
funcName = "basestats"
|
||||||
|
#name of indicator or
|
||||||
|
source = safe_get(params, "source", None)
|
||||||
|
lookback = safe_get(params, "lookback", None)
|
||||||
|
func = safe_get(params, "function", None)
|
||||||
|
|
||||||
|
source_dict = defaultdict(list)
|
||||||
|
source_dict[source] = get_source_series(state, source)
|
||||||
|
|
||||||
|
if lookback is None:
|
||||||
|
source_array = source_dict[source]
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
source_array = source_dict[source][-lookback-1:]
|
||||||
|
except IndexError:
|
||||||
|
source_array = source_dict[source]
|
||||||
|
|
||||||
|
if func == "min":
|
||||||
|
val = np.amin(source_array)
|
||||||
|
elif func == "max":
|
||||||
|
val = np.amax(source_array)
|
||||||
|
elif func == "mean":
|
||||||
|
val = np.mean(source_array)
|
||||||
|
else:
|
||||||
|
return -2, "wrong function"
|
||||||
|
|
||||||
|
return 0, val
|
||||||
|
|
||||||
58
v2realbot/strategyblocks/indicators/custom/conditional.py
Normal file
58
v2realbot/strategyblocks/indicators/custom/conditional.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.indicators.indicators import ema, natr, roc
|
||||||
|
from v2realbot.strategyblocks.indicators.helpers import get_source_series, evaluate_directive_conditions
|
||||||
|
from rich import print as printanyway
|
||||||
|
from traceback import format_exc
|
||||||
|
from v2realbot.ml.ml import ModelML
|
||||||
|
import numpy as np
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
#EXAMPLE of directives:
|
||||||
|
# [stratvars.indicators.novyconditional]
|
||||||
|
# type = "custom"
|
||||||
|
# subtype = "conditional"
|
||||||
|
# on_confirmed_only = true
|
||||||
|
# save_to_past = 5
|
||||||
|
# [stratvars.indicators.novyconditional.cp.conditions.isfalling]
|
||||||
|
# ema200.setindicator_if_falling = 3
|
||||||
|
# true_val = -1
|
||||||
|
# [stratvars.indicators.novyconditional.cp.conditions.isrising]
|
||||||
|
# ema200.setindicator_if_rising = 3
|
||||||
|
# true_val = 1
|
||||||
|
|
||||||
|
#novy podminkovy indikator, muze obsahovat az N podminek ve stejne syntaxy jako u signalu
|
||||||
|
#u kazde podminky je hodnota, ktera se vraci pokud je true
|
||||||
|
#hodi se pro vytvareni binarnich targetu pro ML
|
||||||
|
def conditional(state, params):
|
||||||
|
funcName = "conditional"
|
||||||
|
if params is None:
|
||||||
|
return -2, "params required"
|
||||||
|
conditions = safe_get(params, "conditions", None)
|
||||||
|
if conditions is None:
|
||||||
|
return -2, "conditions required"
|
||||||
|
|
||||||
|
try:
|
||||||
|
#workdict pro kazdou podminku se pripravi v initiu, v conditions mame pak novyatribut workdict
|
||||||
|
#muzeme mit vice podminek, ale prvni True vraci
|
||||||
|
for condname,condsettings in conditions.items():
|
||||||
|
#true davame jednicku default
|
||||||
|
true_val = safe_get(condsettings, "true_val", 1)
|
||||||
|
#printanyway(f"ind {name} podminka {condname} true_val {true_val}")
|
||||||
|
#zde je pripavena podminka, kterou jen evaluujeme
|
||||||
|
cond_dict = condsettings["cond_dict"]
|
||||||
|
result, conditions_met = evaluate_directive_conditions(state, cond_dict, "OR")
|
||||||
|
state.ilog(lvl=1,e=f"IND PODMINKA {condname} =OR= {result}", **conditions_met, cond_dict=cond_dict)
|
||||||
|
if result:
|
||||||
|
return 0, true_val
|
||||||
|
|
||||||
|
#OR neprosly testujeme AND
|
||||||
|
result, conditions_met = evaluate_directive_conditions(state, cond_dict, "AND")
|
||||||
|
state.ilog(lvl=1,e=f"IND PODMINKA {condname} =AND= {result}", **conditions_met, cond_dict=cond_dict)
|
||||||
|
if result:
|
||||||
|
return 0, true_val
|
||||||
|
|
||||||
|
return 0, 0
|
||||||
|
except Exception as e:
|
||||||
|
return -2, str(e)+format_exc()
|
||||||
|
|
||||||
181
v2realbot/strategyblocks/indicators/custom/custom_hub.py
Normal file
181
v2realbot/strategyblocks/indicators/custom/custom_hub.py
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
from rich import print as printanyway
|
||||||
|
from v2realbot.indicators.indicators import ema
|
||||||
|
from traceback import format_exc
|
||||||
|
import importlib
|
||||||
|
|
||||||
|
#TODO TENTO IMPORT VYMYSLET, abych naloadoval package custom a nemusel nic pridat (vymyslet dynamicke volani z cele package ci)
|
||||||
|
#from v2realbot.strategyblocks.indicators.custom._upscaled_rsi_wip import upscaledrsi
|
||||||
|
from v2realbot.strategyblocks.indicators.custom.barparams import barparams
|
||||||
|
from v2realbot.strategyblocks.indicators.custom.basestats import basestats
|
||||||
|
from v2realbot.strategyblocks.indicators.custom.delta import delta
|
||||||
|
from v2realbot.strategyblocks.indicators.custom.divergence import divergence
|
||||||
|
from v2realbot.strategyblocks.indicators.custom.model import model
|
||||||
|
from v2realbot.strategyblocks.indicators.custom.opengap import opengap
|
||||||
|
from v2realbot.strategyblocks.indicators.custom.slope import slope
|
||||||
|
from v2realbot.strategyblocks.indicators.custom.conditional import conditional
|
||||||
|
from v2realbot.strategyblocks.indicators.custom.mathop import mathop
|
||||||
|
|
||||||
|
# import v2realbot.strategyblocks.indicators.custom as ci
|
||||||
|
|
||||||
|
def populate_dynamic_custom_indicator(data, state: StrategyState, name):
|
||||||
|
ind_type = "custom"
|
||||||
|
options = safe_get(state.vars.indicators, name, None)
|
||||||
|
if options is None:
|
||||||
|
state.ilog(lvl=1,e=f"No options for {name} in stratvars")
|
||||||
|
return
|
||||||
|
|
||||||
|
if safe_get(options, "type", False) is False or safe_get(options, "type", False) != ind_type:
|
||||||
|
state.ilog(lvl=1,e="Type error")
|
||||||
|
return
|
||||||
|
|
||||||
|
subtype = safe_get(options, 'subtype', False)
|
||||||
|
if subtype is False:
|
||||||
|
state.ilog(lvl=1,e=f"No subtype for {name} in stratvars")
|
||||||
|
return
|
||||||
|
|
||||||
|
#if MA is required
|
||||||
|
MA_length = safe_get(options, "MA_length", None)
|
||||||
|
|
||||||
|
active = safe_get(options, 'active', True)
|
||||||
|
if not active:
|
||||||
|
return
|
||||||
|
|
||||||
|
# např. 5 - znamená ulož hodnotu indikatoru 5 barů dozadu namísto posledni hodnoty - hodí se pro vytvareni targetu pro ML trening
|
||||||
|
save_to_past = int(safe_get(options, "save_to_past", 0))
|
||||||
|
|
||||||
|
def is_time_to_run():
|
||||||
|
# on_confirmed_only = true (def. False)
|
||||||
|
# start_at_bar_index = 2 (def. None)
|
||||||
|
# start_at_time = "9:31" (def. None)
|
||||||
|
# repeat_every_Nbar = N (def.None) (opakovat každý N bar, 1 - každý bar, 2 - každý 2., 0 - pouze jednou)
|
||||||
|
# repeat_every_Nmin = N (def. None) opakovat každých N minut
|
||||||
|
|
||||||
|
on_confirmed_only = safe_get(options, 'on_confirmed_only', False)
|
||||||
|
start_at_bar_index = safe_get(options, 'start_at_bar_index', None)
|
||||||
|
start_at_time = safe_get(options, 'start_at_time', None) # "9:30"
|
||||||
|
repeat_every_Nbar = safe_get(options, 'repeat_every_Nbar', None)
|
||||||
|
repeat_every_Nmin = safe_get(options, 'repeat_every_Nmin', None)
|
||||||
|
|
||||||
|
#stavové promenne v ramci indikatoru last_run_time a last_run_index - pro repeat_every.. direktivy
|
||||||
|
last_run_time = safe_get(options, 'last_run_time', None)
|
||||||
|
last_run_index = safe_get(options, 'last_run_index', None)
|
||||||
|
|
||||||
|
#confirmed
|
||||||
|
cond = on_confirmed_only is False or (on_confirmed_only is True and data['confirmed']==1)
|
||||||
|
if cond is False:
|
||||||
|
return cond, "not confirmed"
|
||||||
|
|
||||||
|
#start_at_time - v rámci optimalizace presunout do INIT parametru indikátorů, které se naplní v initu a celou dobu se nemění
|
||||||
|
if start_at_time is not None:
|
||||||
|
dt_now = datetime.fromtimestamp(data["updated"]).astimezone(zoneNY)
|
||||||
|
# Parse the maxTime string into a datetime object with the same date as timeA
|
||||||
|
req_start_time = datetime.strptime(start_at_time, "%H:%M").replace(
|
||||||
|
year=dt_now.year, month=dt_now.month, day=dt_now.day)
|
||||||
|
|
||||||
|
# Compare the time components (hours and minutes) of timeA and maxTime
|
||||||
|
if dt_now.time() > req_start_time.time():
|
||||||
|
state.ilog(lvl=0,e=f"IND {name} {subtype} START FROM TIME - PASSED: now:{dt_now.time()} reqtime:{req_start_time.time()}")
|
||||||
|
else:
|
||||||
|
state.ilog(lvl=0,e=f"IND {name} {subtype} START FROM TIME - NOT YET: now:{dt_now.time()} reqtime:{req_start_time.time()}")
|
||||||
|
cond = False
|
||||||
|
|
||||||
|
if cond is False:
|
||||||
|
return cond, "start_at_time not yet"
|
||||||
|
|
||||||
|
#start_on_bar = 0
|
||||||
|
if start_at_bar_index is not None:
|
||||||
|
cond = start_at_bar_index < data["index"]
|
||||||
|
if cond:
|
||||||
|
state.ilog(lvl=0,e=f"IND {name} {subtype} START FROM BAR - PASSED: now:{data['index']} reqbar:{start_at_bar_index}")
|
||||||
|
else:
|
||||||
|
state.ilog(lvl=0,e=f"IND {name} {subtype} START FROM BAR - NOT YET: now:{data['index']} reqbar:{start_at_bar_index}")
|
||||||
|
|
||||||
|
if cond is False:
|
||||||
|
return cond, "start_at_bar_index not yet"
|
||||||
|
|
||||||
|
#pokud 0 - opakujeme jednou, pokud 1 tak opakujeme vzdy, jinak dle poctu
|
||||||
|
if repeat_every_Nbar is not None:
|
||||||
|
#jiz bezelo - delame dalsi checky, pokud nebezelo, poustime jako true
|
||||||
|
if last_run_index is not None:
|
||||||
|
required_bar_to_run = last_run_index + repeat_every_Nbar
|
||||||
|
if repeat_every_Nbar == 0:
|
||||||
|
state.ilog(lvl=0,e=f"IND {name} {subtype} RUN ONCE ALREADY at:{last_run_index} at:{last_run_time}", repeat_every_Nbar=repeat_every_Nbar, last_run_index=last_run_index)
|
||||||
|
cond = False
|
||||||
|
elif repeat_every_Nbar == 1:
|
||||||
|
pass
|
||||||
|
elif data["index"] < required_bar_to_run:
|
||||||
|
state.ilog(lvl=0,e=f"IND {name} {subtype} REPEAT EVERY N BAR WAITING: req:{required_bar_to_run} now:{data['index']}", repeat_every_Nbar=repeat_every_Nbar, last_run_index=last_run_index)
|
||||||
|
cond = False
|
||||||
|
|
||||||
|
if cond is False:
|
||||||
|
return cond, "repeat_every_Nbar not yet"
|
||||||
|
|
||||||
|
#pokud nepozadovano, pak poustime
|
||||||
|
if repeat_every_Nmin is not None:
|
||||||
|
#porovnavame jen pokud uz bezelo
|
||||||
|
if last_run_time is not None:
|
||||||
|
required_time_to_run = last_run_time + timedelta(minutes=repeat_every_Nmin)
|
||||||
|
datetime_now = datetime.fromtimestamp(data["updated"]).astimezone(zoneNY)
|
||||||
|
if datetime_now < required_time_to_run:
|
||||||
|
state.ilog(lvl=0,e=f"IND {name} {subtype} REPEAT EVERY {repeat_every_Nmin}MINS WAITING", last_run_time=last_run_time, required_time_to_run=required_time_to_run, datetime_now=datetime_now)
|
||||||
|
cond = False
|
||||||
|
|
||||||
|
if cond is False:
|
||||||
|
return cond, "repeat_every_Nmin not yet"
|
||||||
|
|
||||||
|
return cond, "ok"
|
||||||
|
|
||||||
|
should_run, msg = is_time_to_run()
|
||||||
|
|
||||||
|
if should_run:
|
||||||
|
#TODO get custom params
|
||||||
|
custom_params = safe_get(options, "cp", None)
|
||||||
|
#vyplnime last_run_time a last_run_index
|
||||||
|
state.vars.indicators[name]["last_run_time"] = datetime.fromtimestamp(data["updated"]).astimezone(zoneNY)
|
||||||
|
state.vars.indicators[name]["last_run_index"] = data["index"]
|
||||||
|
|
||||||
|
# - volame custom funkci pro ziskani hodnoty indikatoru
|
||||||
|
# - tu ulozime jako novou hodnotu indikatoru a prepocteme MAcka pokud je pozadovane
|
||||||
|
# - pokud cas neni, nechavame puvodni, vcetna pripadneho MAcka
|
||||||
|
#pozor jako defaultní hodnotu dává engine 0 - je to ok?
|
||||||
|
try:
|
||||||
|
|
||||||
|
#subtype = "ci."+subtype
|
||||||
|
custom_function = eval(subtype)
|
||||||
|
res_code, new_val = custom_function(state, custom_params)
|
||||||
|
if res_code == 0:
|
||||||
|
state.indicators[name][-1-save_to_past]=new_val
|
||||||
|
state.ilog(lvl=1,e=f"IND {name} {subtype} VAL FROM FUNCTION: {new_val}", lastruntime=state.vars.indicators[name]["last_run_time"], lastrunindex=state.vars.indicators[name]["last_run_index"], save_to_past=save_to_past)
|
||||||
|
#prepocitame MA if required
|
||||||
|
if MA_length is not None:
|
||||||
|
src = state.indicators[name][-MA_length:]
|
||||||
|
MA_res = ema(src, MA_length)
|
||||||
|
MA_value = round(MA_res[-1],7)
|
||||||
|
state.indicators[name+"MA"][-1-save_to_past]=MA_value
|
||||||
|
state.ilog(lvl=0,e=f"IND {name}MA {subtype} {MA_value}",save_to_past=save_to_past)
|
||||||
|
|
||||||
|
else:
|
||||||
|
err = f"IND ERROR {name} {subtype}Funkce {custom_function} vratila {res_code} {new_val}."
|
||||||
|
raise Exception(err)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
if len(state.indicators[name]) >= 2:
|
||||||
|
state.indicators[name][-1]=state.indicators[name][-2]
|
||||||
|
if MA_length is not None and len(state.indicators[name+"MA"])>=2:
|
||||||
|
state.indicators[name+"MA"][-1]=state.indicators[name+"MA"][-2]
|
||||||
|
state.ilog(lvl=1,e=f"IND ERROR {name} {subtype} necháváme původní", message=str(e)+format_exc())
|
||||||
|
|
||||||
|
else:
|
||||||
|
state.ilog(lvl=0,e=f"IND {name} {subtype} COND NOT READY: {msg}")
|
||||||
|
|
||||||
|
#not time to run
|
||||||
|
if len(state.indicators[name]) >= 2:
|
||||||
|
state.indicators[name][-1]=state.indicators[name][-2]
|
||||||
|
|
||||||
|
if MA_length is not None and len(state.indicators[name+"MA"])>=2:
|
||||||
|
state.indicators[name+"MA"][-1]=state.indicators[name+"MA"][-2]
|
||||||
|
|
||||||
|
state.ilog(lvl=0,e=f"IND {name} {subtype} NOT TIME TO RUN - value(and MA) still original")
|
||||||
24
v2realbot/strategyblocks/indicators/custom/delta.py
Normal file
24
v2realbot/strategyblocks/indicators/custom/delta.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.indicators.indicators import ema, natr, roc
|
||||||
|
from v2realbot.strategyblocks.indicators.helpers import get_source_series
|
||||||
|
from rich import print as printanyway
|
||||||
|
from traceback import format_exc
|
||||||
|
from v2realbot.ml.ml import ModelML
|
||||||
|
import numpy as np
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
#strength, absolute change of parameter between current value and lookback value (n-past)
|
||||||
|
#used for example to measure unusual peaks
|
||||||
|
def delta(state, params):
|
||||||
|
funcName = "delta"
|
||||||
|
source = safe_get(params, "source", None)
|
||||||
|
lookback = safe_get(params, "lookback",1)
|
||||||
|
source_series = get_source_series(state, source)
|
||||||
|
|
||||||
|
lookbackval = source_series[-lookback-1]
|
||||||
|
currval = source_series[-1]
|
||||||
|
delta = currval - lookbackval
|
||||||
|
|
||||||
|
state.ilog(lvl=1,e=f"INSIDE {funcName} {delta} {source=} {lookback=}", currval=currval, lookbackval=lookbackval, **params)
|
||||||
|
return 0, delta
|
||||||
43
v2realbot/strategyblocks/indicators/custom/divergence.py
Normal file
43
v2realbot/strategyblocks/indicators/custom/divergence.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.indicators.indicators import ema, natr, roc
|
||||||
|
from v2realbot.strategyblocks.indicators.helpers import get_source_series
|
||||||
|
from rich import print as printanyway
|
||||||
|
from traceback import format_exc
|
||||||
|
from v2realbot.ml.ml import ModelML
|
||||||
|
import numpy as np
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
#abs/rel divergence of two indicators
|
||||||
|
def divergence(state, params):
|
||||||
|
funcName = "indicatorDivergence"
|
||||||
|
source1 = safe_get(params, "source1", None)
|
||||||
|
source1_series = get_source_series(state, source1)
|
||||||
|
source2 = safe_get(params, "source2", None)
|
||||||
|
source2_series = get_source_series(state, source2)
|
||||||
|
mode = safe_get(params, "type")
|
||||||
|
state.ilog(lvl=0,e=f"INSIDE {funcName} {source1=} {source2=} {mode=}", **params)
|
||||||
|
val = 0
|
||||||
|
if mode == "abs":
|
||||||
|
val = round(abs(float(source1_series[-1]) - float(source2_series[-1])),4)
|
||||||
|
elif mode == "absn":
|
||||||
|
val = round((abs(float(source1_series[-1]) - float(source2_series[-1])))/float(source1_series[-1]),4)
|
||||||
|
elif mode == "rel":
|
||||||
|
val = round(float(source1_series[-1]) - float(source2_series[-1]),4)
|
||||||
|
elif mode == "reln":
|
||||||
|
val = round((float(source1_series[-1]) - float(source2_series[-1]))/float(source1_series[-1]),4)
|
||||||
|
elif mode == "pctabs":
|
||||||
|
val = pct_diff(num1=float(source1_series[-1]),num2=float(source2_series[-1]), absolute=True)
|
||||||
|
elif mode == "pct":
|
||||||
|
val = pct_diff(num1=float(source1_series[-1]),num2=float(source2_series[-1]))
|
||||||
|
return 0, val
|
||||||
|
|
||||||
|
#model - naloadovana instance modelu
|
||||||
|
#seq - sekvence pro vstup
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
31
v2realbot/strategyblocks/indicators/custom/mathop.py
Normal file
31
v2realbot/strategyblocks/indicators/custom/mathop.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.strategyblocks.indicators.helpers import get_source_series, value_or_indicator
|
||||||
|
|
||||||
|
#allows basic mathematical operators to one or more indicators (add two indicator, add value to a indicator etc.)
|
||||||
|
def mathop(state, params):
|
||||||
|
funcName = "mathop"
|
||||||
|
#indicator name
|
||||||
|
source1 = safe_get(params, "source1", None)
|
||||||
|
source1_series = get_source_series(state, source1)
|
||||||
|
#indicator or value
|
||||||
|
source2 = safe_get(params, "source2", None)
|
||||||
|
operator = safe_get(params, "operator", None)
|
||||||
|
#state.ilog(lvl=0,e=f"INSIDE {funcName} {source1=} {source2=}", **params)
|
||||||
|
|
||||||
|
if source1 is None or source2 is None or operator is None:
|
||||||
|
return -2, "required source1 source2 operator"
|
||||||
|
if operator == "+":
|
||||||
|
val = round(float(source1_series[-1] + value_or_indicator(state, source2)),4)
|
||||||
|
elif operator == "-":
|
||||||
|
val = round(float(source1_series[-1] - value_or_indicator(state, source2)),4)
|
||||||
|
else:
|
||||||
|
return -2, "unknow operator"
|
||||||
|
#state.ilog(lvl=0,e=f"INSIDE {funcName} {source1=} {source2=} {val}", **params)
|
||||||
|
return 0, val
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
58
v2realbot/strategyblocks/indicators/custom/model.py
Normal file
58
v2realbot/strategyblocks/indicators/custom/model.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.indicators.indicators import ema, natr, roc
|
||||||
|
from v2realbot.strategyblocks.indicators.helpers import get_source_series
|
||||||
|
from rich import print as printanyway
|
||||||
|
from traceback import format_exc
|
||||||
|
from v2realbot.ml.ml import ModelML
|
||||||
|
import numpy as np
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
def model(state, params):
|
||||||
|
funcName = "model"
|
||||||
|
if params is None:
|
||||||
|
return -2, "params required"
|
||||||
|
name = safe_get(params, "name", None)
|
||||||
|
version = safe_get(params, "version", None)
|
||||||
|
|
||||||
|
#TBD co s temito, kdyz se budou brat z uloženého modelu?
|
||||||
|
#mozna jen na TRAIN?
|
||||||
|
# seq = safe_get(params, "seq", None)
|
||||||
|
# use_bars = safe_get(params, "use_bars", True)
|
||||||
|
# bar_features = safe_get(params, "bar_features", None)
|
||||||
|
# ind_features = safe_get(params, "ind_features", None)
|
||||||
|
# if name is None or ind_features is None:
|
||||||
|
# return -2, "name/ind_features required"
|
||||||
|
|
||||||
|
if not name in state.vars.loaded_models:
|
||||||
|
return -2, "model not loaded"
|
||||||
|
|
||||||
|
try:
|
||||||
|
mdl = state.vars.loaded_models[name]
|
||||||
|
if len(state.bars["close"]) < mdl.input_sequences:
|
||||||
|
return 0, 0
|
||||||
|
#return -2, f"too soon - not enough data for seq {seq=}"
|
||||||
|
value = mdl.predict(state.bars, state.indicators)
|
||||||
|
return 0, value
|
||||||
|
except Exception as e:
|
||||||
|
printanyway(str(e)+format_exc())
|
||||||
|
return -2, str(e)+format_exc()
|
||||||
|
|
||||||
|
#presunuto do classy modelu - DECOMISSIONOVAT
|
||||||
|
# def get_model_prediction(cfg: ModelML):
|
||||||
|
# lastNbars = slice_dict_lists(state.bars, cfg.seq, True)
|
||||||
|
# lastNindicators = slice_dict_lists(state.indicators, cfg.seq, False)
|
||||||
|
# combined_live_data = cfg.column_stack_source(lastNbars, lastNindicators)
|
||||||
|
|
||||||
|
# combined_live_data = cfg.scalerX.transform(combined_live_data)
|
||||||
|
# combined_live_data = np.array(combined_live_data)
|
||||||
|
# #converts to 3D array
|
||||||
|
# # 1 number of samples in the array.
|
||||||
|
# # 2 represents the sequence length.
|
||||||
|
# # 3 represents the number of features in the data.
|
||||||
|
# combined_live_data = combined_live_data.reshape((1, cfg.seq, combined_live_data.shape[1]))
|
||||||
|
# #prediction = model.predict(combined_live_data, verbose=0)
|
||||||
|
# prediction = cfg.model(combined_live_data, training=False)
|
||||||
|
|
||||||
|
# # Convert the prediction back to the original scale
|
||||||
|
# return float(cfg.scalerY.inverse_transform(prediction))
|
||||||
22
v2realbot/strategyblocks/indicators/custom/opengap.py
Normal file
22
v2realbot/strategyblocks/indicators/custom/opengap.py
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff
|
||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.indicators.indicators import ema, natr, roc
|
||||||
|
from v2realbot.strategyblocks.indicators.helpers import get_source_series
|
||||||
|
from rich import print as printanyway
|
||||||
|
from traceback import format_exc
|
||||||
|
from v2realbot.ml.ml import ModelML
|
||||||
|
import numpy as np
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
#WIP -
|
||||||
|
#testing custom indicator CODE
|
||||||
|
def opengap(state, params):
|
||||||
|
funcName = "opengap"
|
||||||
|
param1 = safe_get(params, "param1")
|
||||||
|
param2 = safe_get(params, "param2")
|
||||||
|
state.ilog(lvl=0,e=f"INSIDE {funcName} {param1=} {param2=}", **params)
|
||||||
|
last_close = 28.45
|
||||||
|
today_open = 29.45
|
||||||
|
val = pct_diff(last_close, today_open)
|
||||||
|
return 0, val
|
||||||
|
#random.randint(10, 20)
|
||||||
35
v2realbot/strategyblocks/indicators/custom/slope.py
Normal file
35
v2realbot/strategyblocks/indicators/custom/slope.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.indicators.indicators import ema, natr, roc
|
||||||
|
from v2realbot.strategyblocks.indicators.helpers import get_source_series
|
||||||
|
from rich import print as printanyway
|
||||||
|
from traceback import format_exc
|
||||||
|
from v2realbot.ml.ml import ModelML
|
||||||
|
import numpy as np
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
#rate of change - last value of source indicator vs lookback value of lookback_priceline indicator
|
||||||
|
def slope(state, params):
|
||||||
|
funcName = "slope"
|
||||||
|
source = safe_get(params, "source", None)
|
||||||
|
source_series = get_source_series(state, source)
|
||||||
|
|
||||||
|
lookback = safe_get(params, "lookback", 5)
|
||||||
|
lookback_priceline = safe_get(params, "lookback_priceline", None)
|
||||||
|
lookback_series = get_source_series(state, lookback_priceline)
|
||||||
|
|
||||||
|
try:
|
||||||
|
lookbackprice = lookback_series[-lookback-1]
|
||||||
|
lookbacktime = state.bars.updated[-lookback-1]
|
||||||
|
except IndexError:
|
||||||
|
max_delka = len(lookback_series)
|
||||||
|
lookbackprice =lookback_series[-max_delka]
|
||||||
|
lookbacktime = state.bars.updated[-max_delka]
|
||||||
|
|
||||||
|
#výpočet úhlu - a jeho normalizace
|
||||||
|
currval = source_series[-1]
|
||||||
|
slope = ((currval - lookbackprice)/abs(lookbackprice))*100
|
||||||
|
#slope = round(slope, 4)
|
||||||
|
|
||||||
|
state.ilog(lvl=1,e=f"INSIDE {funcName} {slope} {source=} {lookback=}", currval_source=currval, lookbackprice=lookbackprice, lookbacktime=lookbacktime, **params)
|
||||||
|
return 0, slope
|
||||||
38
v2realbot/strategyblocks/indicators/ema.py
Normal file
38
v2realbot/strategyblocks/indicators/ema.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.indicators.indicators import ema, natr, roc
|
||||||
|
from traceback import format_exc
|
||||||
|
|
||||||
|
#EMA INDICATOR
|
||||||
|
# type = EMA, source = [close, vwap, hlcc4], length = [14], on_confirmed_only = [true, false]
|
||||||
|
def populate_dynamic_ema_indicator(data, state: StrategyState, name):
|
||||||
|
ind_type = "EMA"
|
||||||
|
options = safe_get(state.vars.indicators, name, None)
|
||||||
|
if options is None:
|
||||||
|
state.ilog(lvl=1,e=f"No options for {name} in stratvars")
|
||||||
|
return
|
||||||
|
|
||||||
|
if safe_get(options, "type", False) is False or safe_get(options, "type", False) != ind_type:
|
||||||
|
state.ilog(lvl=1,e="Type error")
|
||||||
|
return
|
||||||
|
|
||||||
|
#poustet kazdy tick nebo jenom na confirmed baru (on_confirmed_only = true)
|
||||||
|
on_confirmed_only = safe_get(options, 'on_confirmed_only', False)
|
||||||
|
req_source = safe_get(options, 'source', 'vwap')
|
||||||
|
if req_source not in ["close", "vwap","hlcc4"]:
|
||||||
|
state.ilog(lvl=1,e=f"Unknown source error {req_source} for {name}")
|
||||||
|
return
|
||||||
|
ema_length = int(safe_get(options, "length",14))
|
||||||
|
if on_confirmed_only is False or (on_confirmed_only is True and data['confirmed']==1):
|
||||||
|
try:
|
||||||
|
source = state.bars[req_source][-ema_length:]
|
||||||
|
#if len(source) > ema_length:
|
||||||
|
ema_value = ema(source, ema_length)
|
||||||
|
val = round(ema_value[-1],4)
|
||||||
|
state.indicators[name][-1]= val
|
||||||
|
#state.indicators[name][-1]= round2five(val)
|
||||||
|
state.ilog(lvl=0,e=f"IND {name} EMA {val} {ema_length=}")
|
||||||
|
#else:
|
||||||
|
# state.ilog(lvl=0,e=f"IND {name} EMA necháváme 0", message="not enough source data", source=source, ema_length=ema_length)
|
||||||
|
except Exception as e:
|
||||||
|
state.ilog(lvl=1,e=f"IND ERROR {name} EMA necháváme 0", message=str(e)+format_exc())
|
||||||
87
v2realbot/strategyblocks/indicators/helpers.py
Normal file
87
v2realbot/strategyblocks/indicators/helpers.py
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from traceback import format_exc
|
||||||
|
|
||||||
|
#ZATIM tyto zkopirovany SEM DO HELPERS
|
||||||
|
#podle toho jak se osvedci se zakl.indikatory to s state
|
||||||
|
#zatim se mi to moc nezda
|
||||||
|
|
||||||
|
def value_or_indicator(state,value):
|
||||||
|
#preklad direktivy podle typu, pokud je int anebo float - je to primo hodnota
|
||||||
|
#pokud je str, jde o indikator a dotahujeme posledni hodnotu z nej
|
||||||
|
if isinstance(value, (int, float)):
|
||||||
|
return value
|
||||||
|
elif isinstance(value, str):
|
||||||
|
try:
|
||||||
|
#pokud existuje v indikatoru MA bereme MA jinak indikator, pokud neexistuje bereme bar
|
||||||
|
ret = get_source_or_MA(state, indicator=value)[-1]
|
||||||
|
state.ilog(lvl=0,e=f"Pro porovnani bereme posledni hodnotu {ret} z indikatoru {value}")
|
||||||
|
except Exception as e :
|
||||||
|
ret = 0
|
||||||
|
state.ilog(lvl=1,e=f"Neexistuje indikator s nazvem {value} vracime 0" + str(e) + format_exc())
|
||||||
|
return ret
|
||||||
|
|
||||||
|
#OPTIMALIZOVANO CHATGPT
|
||||||
|
#funkce vytvori podminky (bud pro AND/OR) z pracovniho dict
|
||||||
|
def evaluate_directive_conditions(state, work_dict, cond_type):
|
||||||
|
def rev(kw, condition):
|
||||||
|
if directive.endswith(kw):
|
||||||
|
return not condition
|
||||||
|
else:
|
||||||
|
return condition
|
||||||
|
|
||||||
|
cond = {}
|
||||||
|
cond[cond_type] = {}
|
||||||
|
|
||||||
|
# Create a dictionary to map directives to functions
|
||||||
|
directive_functions = {
|
||||||
|
"above": lambda ind, val: get_source_or_MA(state, ind)[-1] > value_or_indicator(state,val),
|
||||||
|
"equals": lambda ind, val: get_source_or_MA(state, ind)[-1] == value_or_indicator(state,val),
|
||||||
|
"below": lambda ind, val: get_source_or_MA(state, ind)[-1] < value_or_indicator(state,val),
|
||||||
|
"falling": lambda ind, val: isfalling(get_source_or_MA(state, ind), val),
|
||||||
|
"rising": lambda ind, val: isrising(get_source_or_MA(state, ind), val),
|
||||||
|
"crossed_down": lambda ind, val: buy_if_crossed_down(state, ind, value_or_indicator(state,val)),
|
||||||
|
"crossed_up": lambda ind, val: buy_if_crossed_up(state, ind, value_or_indicator(state,val)),
|
||||||
|
"crossed": lambda ind, val: buy_if_crossed_down(state, ind, value_or_indicator(state,val)) or buy_if_crossed_up(state, ind, value_or_indicator(state,val)),
|
||||||
|
"pivot_a": lambda ind, val: is_pivot(source=get_source_or_MA(state, ind), leg_number=val, type="A"),
|
||||||
|
"pivot_v": lambda ind, val: is_pivot(source=get_source_or_MA(state, ind), leg_number=val, type="V"),
|
||||||
|
"still_for": lambda ind, val: is_still(get_source_or_MA(state, ind), val, 2),
|
||||||
|
}
|
||||||
|
|
||||||
|
for indname, directive, value in work_dict[cond_type]:
|
||||||
|
for keyword, func in directive_functions.items():
|
||||||
|
if directive.endswith(keyword):
|
||||||
|
cond[cond_type][directive + "_" + indname + "_" + str(value)] = rev("not_" + keyword, func(indname, value))
|
||||||
|
|
||||||
|
return eval_cond_dict(cond)
|
||||||
|
|
||||||
|
def get_source_or_MA(state, indicator):
|
||||||
|
#pokud ma, pouzije MAcko, pokud ne tak standardni indikator
|
||||||
|
#pokud to jmeno neexistuje, tak pripadne bere z barů (close,open,hlcc4, vwap atp.)
|
||||||
|
try:
|
||||||
|
return state.indicators[indicator+"MA"]
|
||||||
|
except KeyError:
|
||||||
|
try:
|
||||||
|
return state.indicators[indicator]
|
||||||
|
except KeyError:
|
||||||
|
return state.bars[indicator]
|
||||||
|
|
||||||
|
def get_source_series(state, source):
|
||||||
|
try:
|
||||||
|
return state.bars[source]
|
||||||
|
except KeyError:
|
||||||
|
return state.indicators[source]
|
||||||
|
|
||||||
|
#TYTO NEJSPIS DAT do util
|
||||||
|
#vrati true pokud dany indikator prekrocil threshold dolu
|
||||||
|
def buy_if_crossed_down(state, indicator, value):
|
||||||
|
res = crossed_down(threshold=value, list=get_source_or_MA(state, indicator))
|
||||||
|
#state.ilog(lvl=0,e=f"signal_if_crossed_down {indicator} {value} {res}")
|
||||||
|
return res
|
||||||
|
|
||||||
|
#vrati true pokud dany indikator prekrocil threshold nahoru
|
||||||
|
def buy_if_crossed_up(state, indicator, value):
|
||||||
|
res = crossed_up(threshold=value, list=get_source_or_MA(state, indicator))
|
||||||
|
#state.ilog(lvl=0,e=f"signal_if_crossed_up {indicator} {value} {res}")
|
||||||
|
return res
|
||||||
|
|
||||||
100
v2realbot/strategyblocks/indicators/indicators_hub.py
Normal file
100
v2realbot/strategyblocks/indicators/indicators_hub.py
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
|
||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.strategyblocks.indicators.cbar_price import populate_cbar_tick_price_indicator
|
||||||
|
from v2realbot.strategyblocks.indicators.custom.custom_hub import populate_dynamic_custom_indicator
|
||||||
|
from v2realbot.strategyblocks.indicators.slope import populate_dynamic_slope_indicator
|
||||||
|
from v2realbot.strategyblocks.indicators.slopeLP import populate_dynamic_slopeLP_indicator
|
||||||
|
from v2realbot.strategyblocks.indicators.ema import populate_dynamic_ema_indicator
|
||||||
|
from v2realbot.strategyblocks.indicators.RSI import populate_dynamic_RSI_indicator
|
||||||
|
from v2realbot.strategyblocks.indicators.natr import populate_dynamic_natr_indicator
|
||||||
|
from v2realbot.strategyblocks.indicators.atr import populate_dynamic_atr_indicator
|
||||||
|
import numpy as np
|
||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
import json
|
||||||
|
|
||||||
|
def populate_all_indicators(data, state: StrategyState):
|
||||||
|
|
||||||
|
#TYTO MOZNA TAKY POSUNOUT OUT
|
||||||
|
def get_last_ind_vals():
|
||||||
|
last_ind_vals = {}
|
||||||
|
#print(state.indicators.items())
|
||||||
|
for key in state.indicators:
|
||||||
|
if key != 'time':
|
||||||
|
last_ind_vals[key] = state.indicators[key][-6:]
|
||||||
|
|
||||||
|
for key in state.cbar_indicators:
|
||||||
|
if key != 'time':
|
||||||
|
last_ind_vals[key] = state.cbar_indicators[key][-6:]
|
||||||
|
|
||||||
|
# for key in state.secondary_indicators:
|
||||||
|
# if key != 'time':
|
||||||
|
# last_ind_vals[key] = state.secondary_indicators[key][-5:]
|
||||||
|
|
||||||
|
return last_ind_vals
|
||||||
|
#zobrazí jak daleko od sebe chodí updaty (skupiny tradů co mění cenu) a průměr za 50jejich
|
||||||
|
def process_delta():
|
||||||
|
last_update_delta = round((float(data['updated']) - state.vars.last_update_time),6) if state.vars.last_update_time != 0 else 0
|
||||||
|
state.vars.last_update_time = float(data['updated'])
|
||||||
|
|
||||||
|
if len(state.vars.last_50_deltas) >=50:
|
||||||
|
state.vars.last_50_deltas.pop(0)
|
||||||
|
state.vars.last_50_deltas.append(last_update_delta)
|
||||||
|
avg_delta = np.mean(state.vars.last_50_deltas)
|
||||||
|
return last_update_delta, avg_delta
|
||||||
|
|
||||||
|
conf_bar = data['confirmed']
|
||||||
|
last_update_delta, avg_delta = process_delta()
|
||||||
|
|
||||||
|
state.ilog(lvl=1,e=f"-----{data['index']}-{conf_bar}--delta:{last_update_delta}---AVGdelta:{avg_delta}", data=data)
|
||||||
|
|
||||||
|
#kroky pro CONFIRMED BAR only
|
||||||
|
if conf_bar == 1:
|
||||||
|
#logika pouze pro potvrzeny bar
|
||||||
|
state.ilog(lvl=0,e="BAR potvrzeny")
|
||||||
|
|
||||||
|
#pri potvrzem CBARu nulujeme counter volume pro tick based indicator
|
||||||
|
state.vars.last_tick_volume = 0
|
||||||
|
state.vars.next_new = 1
|
||||||
|
#kroky pro CONTINOUS TICKS only
|
||||||
|
else:
|
||||||
|
#CBAR INDICATOR pro tick price a deltu VOLUME
|
||||||
|
populate_cbar_tick_price_indicator(data, state)
|
||||||
|
#TBD nize predelat na typizovane RSI (a to jak na urovni CBAR tak confirmed)
|
||||||
|
#populate_cbar_rsi_indicator()
|
||||||
|
|
||||||
|
#populate indicators, that have type in stratvars.indicators
|
||||||
|
populate_dynamic_indicators(data, state)
|
||||||
|
|
||||||
|
lp = data['close']
|
||||||
|
|
||||||
|
|
||||||
|
#TODO na toto se podivam, nejak moc zajasonovani a zpatky
|
||||||
|
#PERF PROBLEM
|
||||||
|
state.ilog(lvl=1,e="ENTRY", msg=f"LP:{lp} P:{state.positions}/{round(float(state.avgp),3)} SL:{state.vars.activeTrade.stoploss_value if state.vars.activeTrade is not None else None} profit:{round(float(state.profit),2)} Trades:{len(state.tradeList)} pend:{state.vars.pending}", activeTrade=json.loads(json.dumps(state.vars.activeTrade, default=json_serial)), prescribedTrades=json.loads(json.dumps(state.vars.prescribedTrades, default=json_serial)), pending=str(state.vars.pending))
|
||||||
|
inds = get_last_ind_vals()
|
||||||
|
state.ilog(lvl=1,e="Indikatory", **inds)
|
||||||
|
|
||||||
|
def populate_dynamic_indicators(data, state: StrategyState):
|
||||||
|
#pro vsechny indikatory, ktere maji ve svych stratvars TYPE, poustime populaci daneho typu indikaotru
|
||||||
|
for indname, indsettings in state.vars.indicators.items():
|
||||||
|
for option,value in indsettings.items():
|
||||||
|
if option == "type":
|
||||||
|
if value == "slope":
|
||||||
|
populate_dynamic_slope_indicator(data, state, name = indname)
|
||||||
|
#slope variant with continuous Left Point
|
||||||
|
elif value == "slopeLP":
|
||||||
|
populate_dynamic_slopeLP_indicator(data, state, name = indname)
|
||||||
|
elif value == "RSI":
|
||||||
|
populate_dynamic_RSI_indicator(data, state, name = indname)
|
||||||
|
elif value == "EMA":
|
||||||
|
populate_dynamic_ema_indicator(data, state, name = indname)
|
||||||
|
elif value == "NATR":
|
||||||
|
populate_dynamic_natr_indicator(data, state, name = indname)
|
||||||
|
elif value == "ATR":
|
||||||
|
populate_dynamic_atr_indicator(data, state, name = indname)
|
||||||
|
elif value == "custom":
|
||||||
|
populate_dynamic_custom_indicator(data, state, name = indname)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
33
v2realbot/strategyblocks/indicators/natr.py
Normal file
33
v2realbot/strategyblocks/indicators/natr.py
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
from v2realbot.indicators.indicators import ema, natr, roc
|
||||||
|
from v2realbot.indicators.oscillators import rsi
|
||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from traceback import format_exc
|
||||||
|
|
||||||
|
#NATR INDICATOR
|
||||||
|
# type = NATR, ĺength = [14], on_confirmed_only = [true, false]
|
||||||
|
def populate_dynamic_natr_indicator(data, state: StrategyState, name):
|
||||||
|
ind_type = "NATR"
|
||||||
|
options = safe_get(state.vars.indicators, name, None)
|
||||||
|
if options is None:
|
||||||
|
state.ilog(lvl=1,e=f"No options for {name} in stratvars")
|
||||||
|
return
|
||||||
|
|
||||||
|
#poustet kazdy tick nebo jenom na confirmed baru (on_confirmed_only = true)
|
||||||
|
on_confirmed_only = safe_get(options, 'on_confirmed_only', False)
|
||||||
|
natr_length = int(safe_get(options, "length",5))
|
||||||
|
if on_confirmed_only is False or (on_confirmed_only is True and data['confirmed']==1):
|
||||||
|
try:
|
||||||
|
source_high = state.bars["high"][-natr_length:]
|
||||||
|
source_low = state.bars["low"][-natr_length:]
|
||||||
|
source_close = state.bars["close"][-natr_length:]
|
||||||
|
#if len(source) > ema_length:
|
||||||
|
natr_value = natr(source_high, source_low, source_close, natr_length)
|
||||||
|
val = round(natr_value[-1],4)
|
||||||
|
state.indicators[name][-1]= val
|
||||||
|
#state.indicators[name][-1]= round2five(val)
|
||||||
|
state.ilog(lvl=0,e=f"IND {name} NATR {val} {natr_length=}")
|
||||||
|
#else:
|
||||||
|
# state.ilog(lvl=0,e=f"IND {name} EMA necháváme 0", message="not enough source data", source=source, ema_length=ema_length)
|
||||||
|
except Exception as e:
|
||||||
|
state.ilog(lvl=0,e=f"IND ERROR {name} NATR necháváme 0", message=str(e)+format_exc())
|
||||||
132
v2realbot/strategyblocks/indicators/slope.py
Normal file
132
v2realbot/strategyblocks/indicators/slope.py
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.indicators.indicators import ema, natr, roc
|
||||||
|
from v2realbot.indicators.oscillators import rsi
|
||||||
|
import numpy as np
|
||||||
|
from traceback import format_exc
|
||||||
|
|
||||||
|
def populate_dynamic_slope_indicator(data, state: StrategyState, name):
|
||||||
|
options = safe_get(state.vars.indicators, name, None)
|
||||||
|
if options is None:
|
||||||
|
state.ilog(lvl=1,e="No options for slow slope in stratvars")
|
||||||
|
return
|
||||||
|
|
||||||
|
if safe_get(options, "type", False) is False or safe_get(options, "type", False) != "slope":
|
||||||
|
state.ilog(lvl=1,e="Type error")
|
||||||
|
return
|
||||||
|
|
||||||
|
#poustet kazdy tick nebo jenom na confirmed baru (on_confirmed_only = true)
|
||||||
|
on_confirmed_only = safe_get(options, 'on_confirmed_only', False)
|
||||||
|
|
||||||
|
#SLOW SLOPE INDICATOR
|
||||||
|
#úhel stoupání a klesání vyjádřený mezi -1 až 1
|
||||||
|
#pravý bod přímky je aktuální cena, levý je průměr X(lookback offset) starších hodnot od slope_lookback.
|
||||||
|
#VYSTUPY: state.indicators[name],
|
||||||
|
# state.indicators[nameMA]
|
||||||
|
# statický indikátor (angle) - stejneho jmena pro vizualizaci uhlu
|
||||||
|
|
||||||
|
if on_confirmed_only is False or (on_confirmed_only is True and data['confirmed']==1):
|
||||||
|
try:
|
||||||
|
slope_lookback = safe_get(options, 'slope_lookback', 100)
|
||||||
|
lookback_priceline = safe_get(options, 'lookback_priceline', None)
|
||||||
|
lookback_offset = safe_get(options, 'lookback_offset', 25)
|
||||||
|
minimum_slope = safe_get(options, 'minimum_slope', 25)
|
||||||
|
maximum_slope = safe_get(options, "maximum_slope",0.9)
|
||||||
|
|
||||||
|
#jako levy body pouzivame lookback_priceline INDIKATOR vzdaleny slope_lookback barů
|
||||||
|
if lookback_priceline is not None:
|
||||||
|
try:
|
||||||
|
lookbackprice = state.indicators[lookback_priceline][-slope_lookback-1]
|
||||||
|
lookbacktime = state.bars.updated[-slope_lookback-1]
|
||||||
|
except IndexError:
|
||||||
|
max_delka = len(state.indicators[lookback_priceline])
|
||||||
|
lookbackprice = state.indicators[lookback_priceline][-max_delka]
|
||||||
|
lookbacktime = state.bars.updated[-max_delka]
|
||||||
|
|
||||||
|
else:
|
||||||
|
#NEMAME LOOKBACK PRICLINE - pouzivame stary způsob výpočtu, toto pozdeji decomissionovat
|
||||||
|
#lookback has to be even
|
||||||
|
if lookback_offset % 2 != 0:
|
||||||
|
lookback_offset += 1
|
||||||
|
|
||||||
|
#TBD pripdadne /2
|
||||||
|
if len(state.bars.close) > (slope_lookback + lookback_offset):
|
||||||
|
#test prumer nejvyssi a nejnizsi hodnoty
|
||||||
|
# if name == "slope":
|
||||||
|
|
||||||
|
#levy bod bude vzdy vzdaleny o slope_lookback
|
||||||
|
#ten bude prumerem hodnot lookback_offset a to tak ze polovina offsetu z kazde strany
|
||||||
|
array_od = slope_lookback + int(lookback_offset/2)
|
||||||
|
array_do = slope_lookback - int(lookback_offset/2)
|
||||||
|
|
||||||
|
#lookbackprice_array = state.bars.vwap[-array_od:-array_do]
|
||||||
|
#lookbackprice = round(sum(lookbackprice_array)/lookback_offset,3)
|
||||||
|
|
||||||
|
#jako optimalizace pouzijeme NUMPY
|
||||||
|
lookbackprice = np.mean(state.bars.vwap[-array_od:-array_do])
|
||||||
|
# Round the lookback price to 3 decimal places
|
||||||
|
lookbackprice = round(lookbackprice, 3)
|
||||||
|
#lookbackprice = round((min(lookbackprice_array)+max(lookbackprice_array))/2,3)
|
||||||
|
# else:
|
||||||
|
# #puvodni lookback a od te doby dozadu offset
|
||||||
|
# array_od = slope_lookback + lookback_offset
|
||||||
|
# array_do = slope_lookback
|
||||||
|
# lookbackprice_array = state.bars.vwap[-array_od:-array_do]
|
||||||
|
# #obycejný prumer hodnot
|
||||||
|
# lookbackprice = round(sum(lookbackprice_array)/lookback_offset,3)
|
||||||
|
|
||||||
|
lookbacktime = state.bars.time[-slope_lookback]
|
||||||
|
else:
|
||||||
|
#kdyz neni dostatek hodnot, pouzivame jako levy bod open hodnotu close[0]
|
||||||
|
#lookbackprice = state.bars.vwap[0]
|
||||||
|
|
||||||
|
#dalsi vyarianta-- lookback je pole z toho všeho co mame
|
||||||
|
#lookbackprice = Average(state.bars.vwap)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pokud neni dostatek, bereme vzdy prvni petinu z dostupnych barů
|
||||||
|
# a z ní uděláme průměr
|
||||||
|
cnt = len(state.bars.close)
|
||||||
|
if cnt>5:
|
||||||
|
sliced_to = int(cnt/5)
|
||||||
|
|
||||||
|
lookbackprice = np.mean(state.bars.vwap[:sliced_to])
|
||||||
|
#lookbackprice= Average(state.bars.vwap[:sliced_to])
|
||||||
|
lookbacktime = state.bars.time[int(sliced_to/2)]
|
||||||
|
else:
|
||||||
|
lookbackprice = np.mean(state.bars.vwap)
|
||||||
|
#lookbackprice = Average(state.bars.vwap)
|
||||||
|
lookbacktime = state.bars.time[0]
|
||||||
|
|
||||||
|
state.ilog(lvl=1,e=f"IND {name} slope - not enough data bereme left bod open", slope_lookback=slope_lookback, lookbackprice=lookbackprice)
|
||||||
|
|
||||||
|
#výpočet úhlu - a jeho normalizace
|
||||||
|
slope = ((state.bars.close[-1] - lookbackprice)/lookbackprice)*100
|
||||||
|
slope = round(slope, 4)
|
||||||
|
state.indicators[name][-1]=slope
|
||||||
|
|
||||||
|
#angle je ze slope, ale pojmenovavame ho podle MA
|
||||||
|
state.statinds[name] = dict(time=state.bars.time[-1], price=state.bars.close[-1], lookbacktime=lookbacktime, lookbackprice=lookbackprice, minimum_slope=minimum_slope, maximum_slope=maximum_slope)
|
||||||
|
|
||||||
|
#slope MA vyrovna vykyvy ve slope
|
||||||
|
slope_MA_length = safe_get(options, 'MA_length', None)
|
||||||
|
slopeMA = None
|
||||||
|
last_slopesMA = None
|
||||||
|
#pokud je nastavena MA_length tak vytvarime i MAcko dane delky na tento slope
|
||||||
|
if slope_MA_length is not None:
|
||||||
|
source = state.indicators[name][-slope_MA_length:]
|
||||||
|
slopeMAseries = ema(source, slope_MA_length) #state.bars.vwap
|
||||||
|
slopeMA = round(slopeMAseries[-1],4)
|
||||||
|
state.indicators[name+"MA"][-1]=slopeMA
|
||||||
|
last_slopesMA = state.indicators[name+"MA"][-10:]
|
||||||
|
|
||||||
|
lb_priceline_string = "from "+lookback_priceline if lookback_priceline is not None else ""
|
||||||
|
|
||||||
|
state.ilog(lvl=1,e=f"IND {name} {lb_priceline_string} {slope=} {slopeMA=}", msg=f"{lookbackprice=} {lookbacktime=}", lookback_priceline=lookback_priceline, lookbackprice=lookbackprice, lookbacktime=lookbacktime, slope_lookback=slope_lookback, lookbackoffset=lookback_offset, minimum_slope=minimum_slope, last_slopes=state.indicators[name][-10:], last_slopesMA=last_slopesMA)
|
||||||
|
#dale pracujeme s timto MAckovanym slope
|
||||||
|
#slope = slopeMA
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Exception in {name} slope Indicator section", str(e))
|
||||||
|
state.ilog(lvl=1,e=f"EXCEPTION in {name}", msg="Exception in slope Indicator section" + str(e) + format_exc())
|
||||||
124
v2realbot/strategyblocks/indicators/slopeLP.py
Normal file
124
v2realbot/strategyblocks/indicators/slopeLP.py
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.indicators.indicators import ema, natr, roc
|
||||||
|
from v2realbot.indicators.oscillators import rsi
|
||||||
|
from traceback import format_exc
|
||||||
|
#SLOPE LP
|
||||||
|
def populate_dynamic_slopeLP_indicator(data, state: StrategyState, name):
|
||||||
|
ind_type = "slopeLP"
|
||||||
|
options = safe_get(state.vars.indicators, name, None)
|
||||||
|
if options is None:
|
||||||
|
state.ilog(lvl=1,e=f"No options for {name} in stratvars")
|
||||||
|
return
|
||||||
|
|
||||||
|
if safe_get(options, "type", False) is False or safe_get(options, "type", False) != ind_type:
|
||||||
|
state.ilog(lvl=1,e="Type error")
|
||||||
|
return
|
||||||
|
|
||||||
|
#poustet kazdy tick nebo jenom na confirmed baru (on_confirmed_only = true)
|
||||||
|
on_confirmed_only = safe_get(options, 'on_confirmed_only', False)
|
||||||
|
|
||||||
|
#pocet baru po kterých se levy bod z BUY prepne opet na standadni vypocet (prumer)
|
||||||
|
#kdyz se dlouho neprodává a cena nejde dolu, tak aby se nezastavilo nakupovani
|
||||||
|
back_to_standard_after = int(safe_get(options, 'back_to_standard_after', 0))
|
||||||
|
|
||||||
|
#slopeLP INDIKATOR
|
||||||
|
#levy bod je nejdrive standardne automaticky vypočtený podle hodnoty lookbacku (např. -8, offset 4)
|
||||||
|
#při nákupu se BUY POINT se stává levým bodem (až do doby kdy není lookbackprice nižší, pak pokračuje lookbackprice)
|
||||||
|
#při prodeji se SELL POINT se stává novým levým bodem (až do doby kdy není lookbackprice vyšší, pak pokračuje lookbackprice)
|
||||||
|
#zatím implementovat prvni část (mimo části ..až do doby) - tu pak dodelat podle vysledku, pripadne ji neimplementovat vubec a misto toho
|
||||||
|
#udelat slope RESET pri dosazeni urciteho pozitivniho nebo negativni slopu
|
||||||
|
|
||||||
|
#zkusime nejdriv: levy bod automat, po nakupu je levy bod cena nakupu
|
||||||
|
|
||||||
|
#VYSTUPY: state.indicators[name],
|
||||||
|
# state.indicators[nameMA]
|
||||||
|
# statický indikátor (angle) - stejneho jmena pro vizualizaci uhlu
|
||||||
|
|
||||||
|
if on_confirmed_only is False or (on_confirmed_only is True and data['confirmed']==1):
|
||||||
|
try:
|
||||||
|
#slow_slope = 99
|
||||||
|
slope_lookback = safe_get(options, 'slope_lookback', 100)
|
||||||
|
minimum_slope = safe_get(options, 'minimum_slope', 25)
|
||||||
|
maximum_slope = safe_get(options, "maximum_slope",0.9)
|
||||||
|
lookback_offset = safe_get(options, 'lookback_offset', 25)
|
||||||
|
|
||||||
|
#typ leveho bodu [lastbuy - cena posledniho nakupu, baropen - cena otevreni baru]
|
||||||
|
leftpoint = safe_get(options, 'leftpoint', "lastbuy")
|
||||||
|
|
||||||
|
#lookback has to be even
|
||||||
|
if lookback_offset % 2 != 0:
|
||||||
|
lookback_offset += 1
|
||||||
|
|
||||||
|
if leftpoint == "lastbuy":
|
||||||
|
if len(state.bars.close) > (slope_lookback + lookback_offset):
|
||||||
|
#test prumer nejvyssi a nejnizsi hodnoty
|
||||||
|
# if name == "slope":
|
||||||
|
|
||||||
|
#levy bod bude vzdy vzdaleny o slope_lookback
|
||||||
|
#ten bude prumerem hodnot lookback_offset a to tak ze polovina offsetu z kazde strany
|
||||||
|
array_od = slope_lookback + int(lookback_offset/2)
|
||||||
|
array_do = slope_lookback - int(lookback_offset/2)
|
||||||
|
lookbackprice_array = state.bars.vwap[-array_od:-array_do]
|
||||||
|
#cas nastavujeme vzdy podle nastaveni (zatim)
|
||||||
|
lookbacktime = state.bars.time[-slope_lookback]
|
||||||
|
|
||||||
|
#pokud mame aktivni pozice, nastavime lookbackprice a time podle posledniho tradu
|
||||||
|
#pokud se ale dlouho nenakupuje (uplynulo od posledniho nakupu vic nez back_to_standard_after baru), tak se vracime k prumeru
|
||||||
|
if state.avgp > 0 and state.bars.index[-1] < int(state.vars.last_buy_index)+back_to_standard_after:
|
||||||
|
lb_index = -1 - (state.bars.index[-1] - int(state.vars.last_buy_index))
|
||||||
|
lookbackprice = state.bars.vwap[lb_index]
|
||||||
|
state.ilog(lvl=0,e=f"IND {name} slope {leftpoint}- LEFT POINT OVERRIDE bereme ajko cenu lastbuy {lookbackprice=} {lookbacktime=} {lb_index=}")
|
||||||
|
else:
|
||||||
|
#dame na porovnani jen prumer
|
||||||
|
lookbackprice = round(sum(lookbackprice_array)/lookback_offset,3)
|
||||||
|
#lookbackprice = round((min(lookbackprice_array)+max(lookbackprice_array))/2,3)
|
||||||
|
# else:
|
||||||
|
# #puvodni lookback a od te doby dozadu offset
|
||||||
|
# array_od = slope_lookback + lookback_offset
|
||||||
|
# array_do = slope_lookback
|
||||||
|
# lookbackprice_array = state.bars.vwap[-array_od:-array_do]
|
||||||
|
# #obycejný prumer hodnot
|
||||||
|
# lookbackprice = round(sum(lookbackprice_array)/lookback_offset,3)
|
||||||
|
|
||||||
|
lookbacktime = state.bars.time[-slope_lookback]
|
||||||
|
state.ilog(lvl=0,e=f"IND {name} slope {leftpoint} - LEFT POINT STANDARD {lookbackprice=} {lookbacktime=}")
|
||||||
|
else:
|
||||||
|
#kdyz neni dostatek hodnot, pouzivame jako levy bod open hodnotu close[0]
|
||||||
|
lookbackprice = state.bars.close[0]
|
||||||
|
lookbacktime = state.bars.time[0]
|
||||||
|
state.ilog(lvl=0,e=f"IND {name} slope - not enough data bereme left bod open", slope_lookback=slope_lookback)
|
||||||
|
elif leftpoint == "baropen":
|
||||||
|
lookbackprice = state.bars.open[-1]
|
||||||
|
lookbacktime = state.bars.time[-1]
|
||||||
|
state.ilog(lvl=0,e=f"IND {name} slope {leftpoint}- bereme cenu bar OPENu ", lookbackprice=lookbackprice, lookbacktime=lookbacktime)
|
||||||
|
else:
|
||||||
|
state.ilog(lvl=0,e=f"IND {name} UNKNOW LEFT POINT TYPE {leftpoint=}")
|
||||||
|
|
||||||
|
#výpočet úhlu - a jeho normalizace
|
||||||
|
slope = ((state.bars.close[-1] - lookbackprice)/lookbackprice)*100
|
||||||
|
slope = round(slope, 4)
|
||||||
|
state.indicators[name][-1]=slope
|
||||||
|
|
||||||
|
#angle ze slope
|
||||||
|
state.statinds[name] = dict(time=state.bars.updated[-1], price=state.bars.close[-1], lookbacktime=lookbacktime, lookbackprice=lookbackprice, minimum_slope=minimum_slope, maximum_slope=maximum_slope)
|
||||||
|
|
||||||
|
#slope MA vyrovna vykyvy ve slope
|
||||||
|
slope_MA_length = safe_get(options, 'MA_length', None)
|
||||||
|
slopeMA = None
|
||||||
|
last_slopesMA = None
|
||||||
|
#pokud je nastavena MA_length tak vytvarime i MAcko dane delky na tento slope
|
||||||
|
if slope_MA_length is not None:
|
||||||
|
source = state.indicators[name][-slope_MA_length:]
|
||||||
|
slopeMAseries = ema(source, slope_MA_length) #state.bars.vwap
|
||||||
|
slopeMA = round(slopeMAseries[-1],5)
|
||||||
|
state.indicators[name+"MA"][-1]=slopeMA
|
||||||
|
last_slopesMA = state.indicators[name+"MA"][-10:]
|
||||||
|
|
||||||
|
state.ilog(lvl=0,e=f"{name=} {slope=} {slopeMA=}", msg=f"{lookbackprice=}", lookbackoffset=lookback_offset, minimum_slope=minimum_slope, last_slopes=state.indicators[name][-10:], last_slopesMA=last_slopesMA)
|
||||||
|
#dale pracujeme s timto MAckovanym slope
|
||||||
|
#slope = slopeMA
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Exception in {name} slope Indicator section", str(e))
|
||||||
|
state.ilog(lvl=1,e=f"EXCEPTION in {name}", msg="Exception in slope Indicator section" + str(e) + format_exc())
|
||||||
84
v2realbot/strategyblocks/inits/init_directives.py
Normal file
84
v2realbot/strategyblocks/inits/init_directives.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.strategy.StrategyOrderLimitVykladaciNormalizedMYSELL import StrategyOrderLimitVykladaciNormalizedMYSELL
|
||||||
|
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, Followup
|
||||||
|
from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus
|
||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.utils.directive_utils import get_conditions_from_configuration
|
||||||
|
from v2realbot.ml.mlutils import load_model
|
||||||
|
from v2realbot.common.model import SLHistory
|
||||||
|
from v2realbot.config import KW
|
||||||
|
from uuid import uuid4
|
||||||
|
from datetime import datetime
|
||||||
|
#import random
|
||||||
|
import json
|
||||||
|
import numpy as np
|
||||||
|
#from icecream import install, ic
|
||||||
|
from rich import print as printanyway
|
||||||
|
from threading import Event
|
||||||
|
import os
|
||||||
|
from traceback import format_exc
|
||||||
|
|
||||||
|
def intialize_directive_conditions(state):
|
||||||
|
#inciializace pro akce: short, long, dont_short, dont_long, activate
|
||||||
|
|
||||||
|
state.vars.conditions = {}
|
||||||
|
|
||||||
|
#KEYWORDS_if_CONDITION = value
|
||||||
|
# např. go_short_if_below = 10
|
||||||
|
|
||||||
|
#possible KEYWORDS in directive: (AND/OR) support
|
||||||
|
# go_DIRECTION(go_long_if, go_short_if)
|
||||||
|
# dont_go_DIRECTION (dont_long_if, dont_short_if)
|
||||||
|
# exit_DIRECTION (exit_long_if, exit_short_if)
|
||||||
|
# activate (activate_if)
|
||||||
|
|
||||||
|
#possible CONDITIONs:
|
||||||
|
# below, above, falling, rising, crossed_up, crossed_down
|
||||||
|
|
||||||
|
#Tyto mohou byt bud v sekci conditions a nebo v samostatne sekci common
|
||||||
|
|
||||||
|
#pro kazdou sekci "conditions" v signals
|
||||||
|
#si vytvorime podminkove dictionary pro kazdou akci
|
||||||
|
#projdeme vsechny singaly
|
||||||
|
|
||||||
|
|
||||||
|
#nejprve genereujeme ze SIGNALu
|
||||||
|
for signalname, signalsettings in state.vars.signals.items():
|
||||||
|
|
||||||
|
if "conditions" in signalsettings:
|
||||||
|
section = signalsettings["conditions"]
|
||||||
|
|
||||||
|
#directivy non direction related
|
||||||
|
state.vars.conditions.setdefault(KW.activate,{})[signalname] = get_conditions_from_configuration(action=KW.activate+"_if", section=section)
|
||||||
|
|
||||||
|
#direktivy direction related
|
||||||
|
for smer in TradeDirection:
|
||||||
|
#IDEA navrhy condition dictionary - ty v signal sekci
|
||||||
|
# state.vars.conditions["nazev_evaluacni_sekce"]["nazevsignalu_smer"] = #sada podminek
|
||||||
|
#signal related
|
||||||
|
# state.vars.conditions["activate"]["trendfollow"] = #sada podminek
|
||||||
|
# state.vars.conditions["dont_go"]["trendfollow"]["long"] = #sada podminek
|
||||||
|
# state.vars.conditions["go"]["trendfollow"]["short"] = #sada podminek
|
||||||
|
# state.vars.conditions["exit"]["trendfollow"]["long"] = #sada podminek
|
||||||
|
#common
|
||||||
|
# state.vars.conditions["exit"]["common"]["long"] = #sada podminek
|
||||||
|
# state.vars.conditions["exit"]["common"]["long"] = #sada podminek
|
||||||
|
|
||||||
|
state.vars.conditions.setdefault(KW.dont_go,{}).setdefault(signalname,{})[smer] = get_conditions_from_configuration(action=KW.dont_go+"_" + smer +"_if", section=section)
|
||||||
|
state.vars.conditions.setdefault(KW.dont_exit,{}).setdefault(signalname,{})[smer] = get_conditions_from_configuration(action=KW.dont_exit+"_" + smer +"_if", section=section)
|
||||||
|
state.vars.conditions.setdefault(KW.go,{}).setdefault(signalname,{})[smer] = get_conditions_from_configuration(action=KW.go+"_" + smer +"_if", section=section)
|
||||||
|
state.vars.conditions.setdefault(KW.exit,{}).setdefault(signalname,{})[smer] = get_conditions_from_configuration(action=KW.exit+"_" + smer +"_if", section=section)
|
||||||
|
state.vars.conditions.setdefault(KW.reverse,{}).setdefault(signalname,{})[smer] = get_conditions_from_configuration(action=KW.reverse+"_" + smer +"_if", section=section)
|
||||||
|
state.vars.conditions.setdefault(KW.exitadd,{}).setdefault(signalname,{})[smer] = get_conditions_from_configuration(action=KW.exitadd+"_" + smer +"_if", section=section)
|
||||||
|
state.vars.conditions.setdefault(KW.slreverseonly,{}).setdefault(signalname,{})[smer] = get_conditions_from_configuration(action=KW.slreverseonly+"_" + smer +"_if", section=section)
|
||||||
|
# state.vars.work_dict_dont_do[signalname+"_"+ smer] = get_work_dict_with_directive(starts_with=signalname+"_dont_"+ smer +"_if")
|
||||||
|
# state.vars.work_dict_signal_if[signalname+"_"+ smer] = get_work_dict_with_directive(starts_with=signalname+"_"+smer+"_if")
|
||||||
|
|
||||||
|
#POTOM generujeme z obecnych sekci, napr. EXIT.EXIT_CONDITIONS, kde je fallback pro signal exity
|
||||||
|
section = state.vars.exit["conditions"]
|
||||||
|
for smer in TradeDirection:
|
||||||
|
state.vars.conditions.setdefault(KW.exit,{}).setdefault("common",{})[smer] = get_conditions_from_configuration(action=KW.exit+"_" + smer +"_if", section=section)
|
||||||
|
state.vars.conditions.setdefault(KW.dont_exit,{}).setdefault("common",{})[smer] = get_conditions_from_configuration(action=KW.dont_exit+"_" + smer +"_if", section=section)
|
||||||
|
state.vars.conditions.setdefault(KW.reverse,{}).setdefault("common",{})[smer] = get_conditions_from_configuration(action=KW.reverse+"_" + smer +"_if", section=section)
|
||||||
|
state.vars.conditions.setdefault(KW.exitadd,{}).setdefault("common",{})[smer] = get_conditions_from_configuration(action=KW.exitadd+"_" + smer +"_if", section=section)
|
||||||
|
state.vars.conditions.setdefault(KW.slreverseonly,{}).setdefault("common",{})[smer] = get_conditions_from_configuration(action=KW.slreverseonly+"_" + smer +"_if", section=section)
|
||||||
60
v2realbot/strategyblocks/inits/init_indicators.py
Normal file
60
v2realbot/strategyblocks/inits/init_indicators.py
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.strategy.StrategyOrderLimitVykladaciNormalizedMYSELL import StrategyOrderLimitVykladaciNormalizedMYSELL
|
||||||
|
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, Followup
|
||||||
|
from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus
|
||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.utils.directive_utils import get_conditions_from_configuration
|
||||||
|
from v2realbot.ml.mlutils import load_model
|
||||||
|
from v2realbot.common.model import SLHistory
|
||||||
|
from v2realbot.config import KW
|
||||||
|
from uuid import uuid4
|
||||||
|
from datetime import datetime
|
||||||
|
#import random
|
||||||
|
import json
|
||||||
|
import numpy as np
|
||||||
|
#from icecream import install, ic
|
||||||
|
from rich import print as printanyway
|
||||||
|
from threading import Event
|
||||||
|
import os
|
||||||
|
from traceback import format_exc
|
||||||
|
|
||||||
|
def initialize_dynamic_indicators(state):
|
||||||
|
#pro vsechny indikatory, ktere maji ve svych stratvars TYPE inicializujeme
|
||||||
|
dict_copy = state.vars.indicators.copy()
|
||||||
|
for indname, indsettings in dict_copy.items():
|
||||||
|
for option,value in list(indsettings.items()):
|
||||||
|
#inicializujeme nejenom typizovane
|
||||||
|
#if option == "type":
|
||||||
|
state.indicators[indname] = []
|
||||||
|
#pokud ma MA_length incializujeme i MA variantu
|
||||||
|
if safe_get(indsettings, 'MA_length', False):
|
||||||
|
state.indicators[indname+"MA"] = []
|
||||||
|
#specifika pro slope
|
||||||
|
if option == "type":
|
||||||
|
if value == "slope":
|
||||||
|
#inicializujeme statinds (pro uhel na FE)
|
||||||
|
state.statinds[indname] = dict(minimum_slope=safe_get(indsettings, 'minimum_slope', -1), maximum_slope=safe_get(indsettings, 'maximum_slope', 1))
|
||||||
|
if value == "custom":
|
||||||
|
#pro typ custom inicializujeme promenne
|
||||||
|
state.vars.indicators[indname]["last_run_time"] = None
|
||||||
|
state.vars.indicators[indname]["last_run_index"] = None
|
||||||
|
if option == "subtype":
|
||||||
|
if value == "model":
|
||||||
|
active = safe_get(indsettings, 'active', True)
|
||||||
|
if active is False:
|
||||||
|
continue
|
||||||
|
#load the model
|
||||||
|
modelname = safe_get(indsettings["cp"], 'name', None)
|
||||||
|
modelversion = safe_get(indsettings["cp"], 'version', "1")
|
||||||
|
if modelname is not None:
|
||||||
|
state.vars.loaded_models[modelname] = load_model(modelname, modelversion)
|
||||||
|
if state.vars.loaded_models[modelname] is not None:
|
||||||
|
printanyway(f"model {modelname} loaded")
|
||||||
|
else:
|
||||||
|
printanyway(f"ERROR model {modelname} NOT loaded")
|
||||||
|
#pro conditional indikatory projedeme podminky [conditions] a pro kazdou pripravime (cond_dict)
|
||||||
|
if value == "conditional":
|
||||||
|
conditions = state.vars.indicators[indname]["cp"]["conditions"]
|
||||||
|
for condname,condsettings in conditions.items():
|
||||||
|
state.vars.indicators[indname]["cp"]["conditions"][condname]["cond_dict"] = get_conditions_from_configuration(action=KW.change_val+"_if", section=condsettings)
|
||||||
|
printanyway(f'creating workdict for {condname} value {state.vars.indicators[indname]["cp"]["conditions"][condname]["cond_dict"]}')
|
||||||
163
v2realbot/strategyblocks/newtrade/conditions.py
Normal file
163
v2realbot/strategyblocks/newtrade/conditions.py
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.strategy.StrategyOrderLimitVykladaciNormalizedMYSELL import StrategyOrderLimitVykladaciNormalizedMYSELL
|
||||||
|
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, Followup
|
||||||
|
from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus
|
||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get, is_still, is_window_open, eval_cond_dict, crossed_down, crossed_up, crossed, is_pivot, json_serial, pct_diff, create_new_bars, slice_dict_lists
|
||||||
|
from v2realbot.utils.directive_utils import get_conditions_from_configuration
|
||||||
|
from v2realbot.ml.mlutils import load_model
|
||||||
|
from v2realbot.common.model import SLHistory
|
||||||
|
from v2realbot.config import KW
|
||||||
|
from uuid import uuid4
|
||||||
|
from datetime import datetime
|
||||||
|
#import random
|
||||||
|
import json
|
||||||
|
import numpy as np
|
||||||
|
#from icecream import install, ic
|
||||||
|
from rich import print as printanyway
|
||||||
|
from threading import Event
|
||||||
|
import os
|
||||||
|
from traceback import format_exc
|
||||||
|
from v2realbot.strategyblocks.indicators.indicators_hub import populate_all_indicators
|
||||||
|
from v2realbot.strategyblocks.indicators.helpers import evaluate_directive_conditions
|
||||||
|
|
||||||
|
#preconditions and conditions of LONG/SHORT SIGNAL
|
||||||
|
def go_conditions_met(state, data, signalname: str, direction: TradeDirection):
|
||||||
|
if direction == TradeDirection.LONG:
|
||||||
|
smer = "long"
|
||||||
|
else:
|
||||||
|
smer = "short"
|
||||||
|
#preconditiony dle smer
|
||||||
|
|
||||||
|
#SPECIFICKE DONT BUYS - direktivy zacinajici dont_buy
|
||||||
|
#dont_buy_below = value nebo nazev indikatoru
|
||||||
|
#dont_buy_above = value nebo hazev indikatoru
|
||||||
|
|
||||||
|
#TESTUJEME SPECIFICKY DONT_GO -
|
||||||
|
#u techto ma smysl pouze OR
|
||||||
|
cond_dict = state.vars.conditions[KW.dont_go][signalname][smer]
|
||||||
|
result, conditions_met = evaluate_directive_conditions(state, cond_dict, "OR")
|
||||||
|
state.ilog(lvl=1,e=f"SPECIFIC PRECOND {smer} {result}", **conditions_met, cond_dict=cond_dict)
|
||||||
|
if result:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# #OR neprosly testujeme AND
|
||||||
|
# result, conditions_met = evaluate_directive_conditions(cond_dict, "AND")
|
||||||
|
# state.ilog(lvl=0,e=f"EXIT CONDITIONS of activeTrade {smer} =AND= {result}", **conditions_met, cond_dict=cond_dict)
|
||||||
|
# if result:
|
||||||
|
# return True
|
||||||
|
|
||||||
|
#tyto timto nahrazeny - dat do konfigurace (dont_short_when, dont_long_when)
|
||||||
|
#dont_buy_when['rsi_too_high'] = state.indicators.RSI14[-1] > safe_get(state.vars, "rsi_dont_buy_above",50)
|
||||||
|
#dont_buy_when['slope_too_low'] = slope_too_low()
|
||||||
|
#dont_buy_when['slope_too_high'] = slope_too_high()
|
||||||
|
#dont_buy_when['rsi_is_zero'] = (state.indicators.RSI14[-1] == 0)
|
||||||
|
#dont_buy_when['reverse_position_waiting_amount_not_0'] = (state.vars.reverse_position_waiting_amount != 0)
|
||||||
|
|
||||||
|
#u indikatoru muzoun byt tyto directivy pro generovani signaliu long/short
|
||||||
|
# long_if_crossed_down - kdyz prekrocil dolu, VALUE: hodnota nebo nazev indikatoru
|
||||||
|
# long_if_crossed_up - kdyz prekrocil nahoru, VALUE: hodnota nebo nazev indikatoru
|
||||||
|
# long_if_crossed - kdyz krosne obema smery, VALUE: hodnota nebo nazev indikatoru
|
||||||
|
# long_if_falling - kdyz je klesajici po N, VALUE: hodnota
|
||||||
|
# long_if_rising - kdyz je rostouci po N, VALUE: hodnota
|
||||||
|
# long_if_below - kdyz je pod prahem, VALUE: hodnota nebo nazev indikatoru
|
||||||
|
# long_if_above - kdyz je nad prahem, VALUE: hodnota nebo nazev indikatoru
|
||||||
|
# long_if_pivot_a - kdyz je pivot A. VALUE: delka nohou
|
||||||
|
# long_if_pivot_v - kdyz je pivot V. VALUE: delka nohou
|
||||||
|
|
||||||
|
# direktivy se mohou nachazet v podsekci AND nebo OR - daneho indikatoru (nebo na volno, pak = OR)
|
||||||
|
# OR - staci kdyz plati jedna takova podminka a buysignal je aktivni
|
||||||
|
# AND - musi platit vsechny podminky ze vsech indikatoru, aby byl buysignal aktivni
|
||||||
|
|
||||||
|
#populate work dict - muze byt i jen jednou v INIT nebo 1x za cas
|
||||||
|
#dict oindexovane podminkou (OR/AND) obsahuje vsechny buy_if direktivy v tuplu (nazevind,direktiva,hodnota
|
||||||
|
# {'AND': [('nazev indikatoru', 'nazev direktivy', 'hodnotadirektivy')], 'OR': []}
|
||||||
|
#work_dict_signal_if = get_work_dict_with_directive(starts_with=signalname+"_"+smer+"_if")
|
||||||
|
|
||||||
|
#TESTUJEME GO SIGNAL
|
||||||
|
cond_dict = state.vars.conditions[KW.go][signalname][smer]
|
||||||
|
result, conditions_met = evaluate_directive_conditions(state, cond_dict, "OR")
|
||||||
|
state.ilog(lvl=1,e=f"EVAL GO SIGNAL {smer} =OR= {result}", **conditions_met, cond_dict=cond_dict)
|
||||||
|
if result:
|
||||||
|
return True
|
||||||
|
|
||||||
|
#OR neprosly testujeme AND
|
||||||
|
result, conditions_met = evaluate_directive_conditions(state, cond_dict, "AND")
|
||||||
|
state.ilog(lvl=1,e=f"EVAL GO SIGNAL {smer} =AND= {result}", **conditions_met, cond_dict=cond_dict)
|
||||||
|
if result:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
#obecne precondition preds vstupem - platne jak pro condition based tak pro plugin
|
||||||
|
def common_go_preconditions_check(state, data, signalname: str, options: dict):
|
||||||
|
#ZAKLADNI KONTROLY ATRIBUTU s fallbackem na obecné
|
||||||
|
#check working windows (open - close, in minutes from the start of marker)
|
||||||
|
|
||||||
|
window_open = safe_get(options, "window_open",safe_get(state.vars, "window_open",0))
|
||||||
|
window_close = safe_get(options, "window_close",safe_get(state.vars, "window_close",390))
|
||||||
|
|
||||||
|
if is_window_open(datetime.fromtimestamp(data['updated']).astimezone(zoneNY), window_open, window_close) is False:
|
||||||
|
state.ilog(lvl=1,e=f"SIGNAL {signalname} - WINDOW CLOSED", msg=f"{window_open=} {window_close=} ")
|
||||||
|
return False
|
||||||
|
|
||||||
|
min_bar_index = safe_get(options, "min_bar_index",safe_get(state.vars, "min_bar_index",0))
|
||||||
|
if int(data["index"]) < int(min_bar_index):
|
||||||
|
state.ilog(lvl=1,e=f"MIN BAR INDEX {min_bar_index} waiting - TOO SOON", currindex=data["index"])
|
||||||
|
return False
|
||||||
|
|
||||||
|
next_signal_offset = safe_get(options, "next_signal_offset_from_last_exit",safe_get(state.vars, "next_signal_offset_from_last_exit",0))
|
||||||
|
|
||||||
|
if state.vars.last_exit_index is not None:
|
||||||
|
index_to_compare = int(state.vars.last_exit_index)+int(next_signal_offset)
|
||||||
|
if index_to_compare > int(data["index"]):
|
||||||
|
state.ilog(lvl=1,e=f"NEXT SIGNAL OFFSET from EXIT {next_signal_offset} waiting - TOO SOON", currindex=data["index"], index_to_compare=index_to_compare, last_exit_index=state.vars.last_exit_index)
|
||||||
|
return False
|
||||||
|
|
||||||
|
# if is_open_rush(datetime.fromtimestamp(data['updated']).astimezone(zoneNY), open_rush) or is_close_rush(datetime.fromtimestamp(data['updated']).astimezone(zoneNY), close_rush):
|
||||||
|
# state.ilog(lvl=0,e=f"SIGNAL {signalname} - WINDOW CLOSED", msg=f"{open_rush=} {close_rush=} ")
|
||||||
|
# return False
|
||||||
|
|
||||||
|
#natvrdo nebo na podminku
|
||||||
|
activated = safe_get(options, "activated", True)
|
||||||
|
|
||||||
|
#check activation
|
||||||
|
if activated is False:
|
||||||
|
state.ilog(lvl=1,e=f"{signalname} not ACTIVATED")
|
||||||
|
cond_dict = state.vars.conditions[KW.activate][signalname]
|
||||||
|
result, conditions_met = evaluate_directive_conditions(state, cond_dict, "OR")
|
||||||
|
state.ilog(lvl=1,e=f"EVAL ACTIVATION CONDITION =OR= {result}", **conditions_met, cond_dict=cond_dict)
|
||||||
|
|
||||||
|
if result is False:
|
||||||
|
#OR neprosly testujeme AND
|
||||||
|
result, conditions_met = evaluate_directive_conditions(state, cond_dict, "AND")
|
||||||
|
state.ilog(lvl=1,e=f"EVAL ACTIVATION CONDITION =AND= {result}", **conditions_met, cond_dict=cond_dict)
|
||||||
|
|
||||||
|
if result is False:
|
||||||
|
state.ilog(lvl=1,e=f"not ACTIVATED")
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
state.ilog(lvl=1,e=f"{signalname} JUST ACTIVATED")
|
||||||
|
state.vars.signals[signalname]["activated"] = True
|
||||||
|
|
||||||
|
# OBECNE PRECONDITIONS - typu dont_do_when
|
||||||
|
precond_check = dict(AND=dict(), OR=dict())
|
||||||
|
|
||||||
|
# #OBECNE DONT BUYS
|
||||||
|
if safe_get(options, "signal_only_on_confirmed",safe_get(state.vars, "signal_only_on_confirmed",True)):
|
||||||
|
precond_check['bar_not_confirmed'] = (data['confirmed'] == 0)
|
||||||
|
# #od posledniho vylozeni musi ubehnout N baru
|
||||||
|
# dont_buy_when['last_buy_offset_too_soon'] = data['index'] < (int(state.vars.lastbuyindex) + int(safe_get(state.vars, "lastbuy_offset",3)))
|
||||||
|
# dont_buy_when['blockbuy_active'] = (state.vars.blockbuy == 1)
|
||||||
|
# dont_buy_when['jevylozeno_active'] = (state.vars.jevylozeno == 1)
|
||||||
|
|
||||||
|
#obecne open_rush platne pro vsechny
|
||||||
|
#precond_check['on_confirmed_only'] = safe_get(options, 'on_confirmed_only', False) - chybi realizace podminky, pripadne dodelat na short_on_confirmed
|
||||||
|
|
||||||
|
# #testing preconditions
|
||||||
|
result, cond_met = eval_cond_dict(precond_check)
|
||||||
|
if result:
|
||||||
|
state.ilog(lvl=1,e=f"PRECOND GENERAL not met {cond_met}", message=cond_met, precond_check=precond_check)
|
||||||
|
return False
|
||||||
|
|
||||||
|
state.ilog(lvl=1,e=f"{signalname} ALL PRECOND MET")
|
||||||
|
return True
|
||||||
2
v2realbot/strategyblocks/newtrade/plugins/asr.py
Normal file
2
v2realbot/strategyblocks/newtrade/plugins/asr.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#ASR signal plugin
|
||||||
|
#WIP
|
||||||
78
v2realbot/strategyblocks/newtrade/prescribedtrades.py
Normal file
78
v2realbot/strategyblocks/newtrade/prescribedtrades.py
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.common.PrescribedTradeModel import TradeDirection, TradeStatus
|
||||||
|
from v2realbot.utils.utils import zoneNY, json_serial
|
||||||
|
from datetime import datetime
|
||||||
|
#import random
|
||||||
|
import json
|
||||||
|
from v2realbot.strategyblocks.activetrade.helpers import insert_SL_history, get_default_sl_value, normalize_tick
|
||||||
|
|
||||||
|
def execute_prescribed_trades(state: StrategyState, data):
|
||||||
|
##evaluate prescribed trade, prvni eligible presuneme do activeTrade, zmenime stav and vytvorime objednavky
|
||||||
|
|
||||||
|
if state.vars.activeTrade is not None or len(state.vars.prescribedTrades) == 0:
|
||||||
|
return
|
||||||
|
#evaluate long (price/market)
|
||||||
|
state.ilog(lvl=1,e="evaluating prescr trades", trades=json.loads(json.dumps(state.vars.prescribedTrades, default=json_serial)))
|
||||||
|
for trade in state.vars.prescribedTrades:
|
||||||
|
if trade.status == TradeStatus.READY and trade.direction == TradeDirection.LONG and (trade.entry_price is None or trade.entry_price >= data['close']):
|
||||||
|
trade.status = TradeStatus.ACTIVATED
|
||||||
|
trade.last_update = datetime.fromtimestamp(state.time).astimezone(zoneNY)
|
||||||
|
state.ilog(lvl=1,e=f"evaluated LONG", trade=json.loads(json.dumps(trade, default=json_serial)), prescrTrades=json.loads(json.dumps(state.vars.prescribedTrades, default=json_serial)))
|
||||||
|
state.vars.activeTrade = trade
|
||||||
|
state.vars.last_buy_index = data["index"]
|
||||||
|
state.vars.last_in_index = data["index"]
|
||||||
|
break
|
||||||
|
#evaluate shorts
|
||||||
|
if not state.vars.activeTrade:
|
||||||
|
for trade in state.vars.prescribedTrades:
|
||||||
|
if trade.status == TradeStatus.READY and trade.direction == TradeDirection.SHORT and (trade.entry_price is None or trade.entry_price <= data['close']):
|
||||||
|
state.ilog(lvl=1,e=f"evaluaed SHORT", trade=json.loads(json.dumps(trade, default=json_serial)), prescTrades=json.loads(json.dumps(state.vars.prescribedTrades, default=json_serial)))
|
||||||
|
trade.status = TradeStatus.ACTIVATED
|
||||||
|
trade.last_update = datetime.fromtimestamp(state.time).astimezone(zoneNY)
|
||||||
|
state.vars.activeTrade = trade
|
||||||
|
state.vars.last_buy_index = data["index"]
|
||||||
|
state.vars.last_in_index = data["index"]
|
||||||
|
break
|
||||||
|
|
||||||
|
#odeslani ORDER + NASTAVENI STOPLOSS (zatim hardcoded)
|
||||||
|
if state.vars.activeTrade:
|
||||||
|
if state.vars.activeTrade.direction == TradeDirection.LONG:
|
||||||
|
state.ilog(lvl=1,e="odesilame LONG ORDER", trade=json.loads(json.dumps(state.vars.activeTrade, default=json_serial)))
|
||||||
|
if state.vars.activeTrade.size is not None:
|
||||||
|
size = state.vars.activeTrade.size
|
||||||
|
else:
|
||||||
|
size = state.vars.chunk
|
||||||
|
res = state.buy(size=size)
|
||||||
|
if isinstance(res, int) and res < 0:
|
||||||
|
raise Exception(f"error in required operation LONG {res}")
|
||||||
|
#nastaveni SL az do notifikace, kdy je známá
|
||||||
|
#pokud neni nastaveno SL v prescribe, tak nastavuji default dle stratvars
|
||||||
|
if state.vars.activeTrade.stoploss_value is None:
|
||||||
|
sl_defvalue = get_default_sl_value(state, direction=state.vars.activeTrade.direction)
|
||||||
|
#normalizuji dle aktualni ceny
|
||||||
|
sl_defvalue_normalized = normalize_tick(state, data,sl_defvalue)
|
||||||
|
state.vars.activeTrade.stoploss_value = float(data['close']) - sl_defvalue_normalized
|
||||||
|
insert_SL_history(state)
|
||||||
|
state.ilog(lvl=1,e=f"Nastaveno SL na {sl_defvalue}, priced normalized: {sl_defvalue_normalized} price: {state.vars.activeTrade.stoploss_value }")
|
||||||
|
state.vars.pending = state.vars.activeTrade.id
|
||||||
|
elif state.vars.activeTrade.direction == TradeDirection.SHORT:
|
||||||
|
state.ilog(lvl=1,e="odesilame SHORT ORDER",trade=json.loads(json.dumps(state.vars.activeTrade, default=json_serial)))
|
||||||
|
if state.vars.activeTrade.size is not None:
|
||||||
|
size = state.vars.activeTrade.size
|
||||||
|
else:
|
||||||
|
size = state.vars.chunk
|
||||||
|
res = state.sell(size=size)
|
||||||
|
if isinstance(res, int) and res < 0:
|
||||||
|
raise Exception(f"error in required operation SHORT {res}")
|
||||||
|
#pokud neni nastaveno SL v prescribe, tak nastavuji default dle stratvars
|
||||||
|
if state.vars.activeTrade.stoploss_value is None:
|
||||||
|
sl_defvalue = get_default_sl_value(state, direction=state.vars.activeTrade.direction)
|
||||||
|
#normalizuji dle aktualni ceny
|
||||||
|
sl_defvalue_normalized = normalize_tick(state, data, sl_defvalue)
|
||||||
|
state.vars.activeTrade.stoploss_value = float(data['close']) + sl_defvalue_normalized
|
||||||
|
insert_SL_history(state)
|
||||||
|
state.ilog(lvl=1,e=f"Nastaveno SL na {sl_defvalue}, priced normalized: {sl_defvalue_normalized} price: {state.vars.activeTrade.stoploss_value }")
|
||||||
|
state.vars.pending = state.vars.activeTrade.id
|
||||||
|
else:
|
||||||
|
state.ilog(lvl=1,e="unknow direction")
|
||||||
|
state.vars.activeTrade = None
|
||||||
92
v2realbot/strategyblocks/newtrade/signals.py
Normal file
92
v2realbot/strategyblocks/newtrade/signals.py
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
from v2realbot.strategy.base import StrategyState
|
||||||
|
from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus
|
||||||
|
from v2realbot.utils.utils import isrising, isfalling,zoneNY, price2dec, print, safe_get
|
||||||
|
from v2realbot.config import KW
|
||||||
|
from uuid import uuid4
|
||||||
|
from datetime import datetime
|
||||||
|
from rich import print as printanyway
|
||||||
|
from traceback import format_exc
|
||||||
|
from v2realbot.strategyblocks.newtrade.conditions import go_conditions_met, common_go_preconditions_check
|
||||||
|
|
||||||
|
def signal_search(state: StrategyState, data):
|
||||||
|
# SIGNAL sekce ve stratvars obsahuje signaly: Ty se skladaji z obecnych parametru a podsekce podminek.
|
||||||
|
# Obecne parametry mohou overridnout root parametry nebo dalsi upresneni(napr. plugin). Podsekce CONDITIONS,obsahuji podminky vstup a vystupu
|
||||||
|
# OBECNE:
|
||||||
|
# [stratvars.signals.trend2]
|
||||||
|
# signal_only_on_confirmed = true
|
||||||
|
# open_rush = 2
|
||||||
|
# close_rush = 6000
|
||||||
|
# short_enabled = false
|
||||||
|
# long_enabled = false
|
||||||
|
# activated = true
|
||||||
|
# profit = 0.2
|
||||||
|
# max_profit = 0.4
|
||||||
|
# PODMINKY:
|
||||||
|
# [stratvars.signals.trend2.conditions]
|
||||||
|
# slope20.AND.in_long_if_above = 0.23
|
||||||
|
# slope10.AND.in_long_if_rising = 5
|
||||||
|
# slope10.out_long_if_crossed_down = -0.1
|
||||||
|
# slope10.in_short_if_crossed_down = -0.1
|
||||||
|
# slope10.out_short_if_above = 0
|
||||||
|
# ema.AND.short_if_below = 28
|
||||||
|
|
||||||
|
for signalname, signalsettings in state.vars.signals.items():
|
||||||
|
execute_signal_generator(state, data, signalname)
|
||||||
|
|
||||||
|
# #vysledek je vložení Trade Prescription a to bud s cenou nebo immediate
|
||||||
|
# pokud je s cenou ceka se na cenu, pokud immmediate tak se hned provede
|
||||||
|
# to vse za predpokladu, ze neni aktivni trade
|
||||||
|
|
||||||
|
def execute_signal_generator(state, data, name):
|
||||||
|
state.ilog(lvl=0,e=f"SIGNAL SEARCH for {name}", cond_go=state.vars.conditions[KW.go][name], cond_dontgo=state.vars.conditions[KW.dont_go][name], cond_activate=state.vars.conditions[KW.activate][name] )
|
||||||
|
options = safe_get(state.vars.signals, name, None)
|
||||||
|
|
||||||
|
if options is None:
|
||||||
|
state.ilog(lvl=1,e="No options for {name} in stratvars")
|
||||||
|
return
|
||||||
|
|
||||||
|
if common_go_preconditions_check(state, data, signalname=name, options=options) is False:
|
||||||
|
return
|
||||||
|
|
||||||
|
# signal_plugin = "reverzni"
|
||||||
|
# signal_plugin_run_once_at_index = 3
|
||||||
|
#pokud existuje plugin, tak pro signal search volame plugin a ignorujeme conditiony
|
||||||
|
signal_plugin = safe_get(options, 'plugin', None)
|
||||||
|
signal_plugin_run_once_at_index = safe_get(options, 'signal_plugin_run_once_at_index', 3)
|
||||||
|
|
||||||
|
#pokud je plugin True, spusti se kod
|
||||||
|
if signal_plugin is not None and signal_plugin_run_once_at_index==data["index"]:
|
||||||
|
try:
|
||||||
|
custom_function = eval(signal_plugin)
|
||||||
|
custom_function()
|
||||||
|
except NameError:
|
||||||
|
state.ilog(lvl=1,e="Custom plugin {signal_plugin} not found")
|
||||||
|
else:
|
||||||
|
short_enabled = safe_get(options, "short_enabled",safe_get(state.vars, "short_enabled",True))
|
||||||
|
long_enabled = safe_get(options, "long_enabled",safe_get(state.vars, "long_enabled",True))
|
||||||
|
#common signals based on 1) configured signals in stratvars
|
||||||
|
#toto umoznuje jednoduchy prescribed trade bez ceny
|
||||||
|
if short_enabled is False:
|
||||||
|
state.ilog(lvl=1,e=f"{name} SHORT DISABLED")
|
||||||
|
if long_enabled is False:
|
||||||
|
state.ilog(lvl=1,e=f"{name} LONG DISABLED")
|
||||||
|
if long_enabled and go_conditions_met(state, data,signalname=name, direction=TradeDirection.LONG):
|
||||||
|
state.vars.prescribedTrades.append(Trade(
|
||||||
|
id=uuid4(),
|
||||||
|
last_update=datetime.fromtimestamp(state.time).astimezone(zoneNY),
|
||||||
|
status=TradeStatus.READY,
|
||||||
|
generated_by=name,
|
||||||
|
direction=TradeDirection.LONG,
|
||||||
|
entry_price=None,
|
||||||
|
stoploss_value = None))
|
||||||
|
elif short_enabled and go_conditions_met(state, data, signalname=name, direction=TradeDirection.SHORT):
|
||||||
|
state.vars.prescribedTrades.append(Trade(
|
||||||
|
id=uuid4(),
|
||||||
|
last_update=datetime.fromtimestamp(state.time).astimezone(zoneNY),
|
||||||
|
status=TradeStatus.READY,
|
||||||
|
generated_by=name,
|
||||||
|
direction=TradeDirection.SHORT,
|
||||||
|
entry_price=None,
|
||||||
|
stoploss_value = None))
|
||||||
|
else:
|
||||||
|
state.ilog(lvl=0,e=f"{name} NO SIGNAL")
|
||||||
@ -19,6 +19,10 @@ def get_conditions_from_configuration(action: str, section: dict):
|
|||||||
|
|
||||||
for indname, condition in section.items():
|
for indname, condition in section.items():
|
||||||
#prvnim je vzdy indikator na ktery se direktiva odkazuje, tzn. projedeme vsechny tyto indikatory
|
#prvnim je vzdy indikator na ktery se direktiva odkazuje, tzn. projedeme vsechny tyto indikatory
|
||||||
|
|
||||||
|
# #pokud je zde neco jineho nez dict, tak ignorujeme
|
||||||
|
if not isinstance(condition, dict):
|
||||||
|
continue
|
||||||
for directive, value in condition.items():
|
for directive, value in condition.items():
|
||||||
if directive.startswith(action):
|
if directive.startswith(action):
|
||||||
reslist["OR"].append((indname, directive, value))
|
reslist["OR"].append((indname, directive, value))
|
||||||
|
|||||||
Reference in New Issue
Block a user