finalni instant indikatory + save do arch

This commit is contained in:
David Brazda
2023-10-24 18:49:39 +02:00
parent 0c4fb20c66
commit de5382d04a
17 changed files with 455 additions and 234 deletions

View File

@ -1,19 +1,32 @@
import v2realbot.controller.services as cs
from v2realbot.common.model import RunDay, StrategyInstance, Runner, RunRequest, RunArchive, RunArchiveView, RunArchiveDetail, RunArchiveChange, Bar, TradeEvent, TestList, Intervals, ConfigItem, InstantIndicator
#[stratvars.indicators.vwma]
runner_id = "b44d6d8f-b44d-45b1-ad7a-7ee8b0facead"
runner_id = "1ac42f29-b902-44df-9bd6-e2a430989705"
toml = """
type = "custom"
subtype = "vwma"
#[stratvars.indicators.cross]
type = 'custom'
subtype = 'conditional'
on_confirmed_only = true
cp.source = "vwap"
cp.ref_source = "volume"
cp.lookback = 50
[cp.conditions.crossdown]
vwap.change_val_if_crossed_down = 'emaSlow'
true_val = -1
[cp.conditions.crossup]
vwap.change_val_if_crossed_up = 'emaSlow'
true_val = 1
"""
res, vals = cs.preview_indicator_byTOML(id=runner_id, toml=toml)
toml = """
#[stratvars.indicators.rsi14]
type = 'RSI'
source = 'vwap'
length = 14
on_confirmed_only = true
"""
indicator = InstantIndicator(name="rsi14alt", toml=toml)
res, vals = cs.preview_indicator_byTOML(id=runner_id, indicator=indicator)
print(res)
print(vals)

View File

@ -86,7 +86,7 @@ if save_new_ind:
sada["indicators"][0]["pred_added"] = ind_pred
req = update_archive_detail(runner_id, sada)
req, res = update_archive_detail(runner_id, sada)
print(f"indicator pred_added was ADDED to {runner_id}")

View File

@ -31,7 +31,7 @@ class ConnectionPool:
return connection
def execute_with_retry(cursor: sqlite3.Cursor, statement: str, retry_interval: int = 1) -> sqlite3.Cursor:
def execute_with_retry(cursor: sqlite3.Cursor, statement: str, params = None, retry_interval: int = 1) -> sqlite3.Cursor:
"""get connection from pool and execute SQL statement with retry logic if required.
Args:
@ -44,7 +44,10 @@ def execute_with_retry(cursor: sqlite3.Cursor, statement: str, retry_interval: i
"""
while True:
try:
if params is None:
return cursor.execute(statement)
else:
return cursor.execute(statement, params)
except sqlite3.OperationalError as e:
if str(e) == "database is locked":
print("database retry in 1s." + str(e))

View File

@ -267,9 +267,9 @@ class RunArchiveDetail(BaseModel):
trades: List[TradeUpdate]
ext_data: Optional[dict]
class TomlInput(BaseModel):
toml: str
# class Trade(BaseModel):
# order: Order
# value: float
class InstantIndicator(BaseModel):
name: str
toml: str

View File

@ -7,7 +7,7 @@ from alpaca.data.enums import DataFeed
from alpaca.data.timeframe import TimeFrame
from v2realbot.strategy.base import StrategyState
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide
from v2realbot.common.model import RunDay, StrategyInstance, Runner, RunRequest, RunArchive, RunArchiveView, RunArchiveDetail, RunArchiveChange, Bar, TradeEvent, TestList, Intervals, ConfigItem
from v2realbot.common.model import RunDay, StrategyInstance, Runner, RunRequest, RunArchive, RunArchiveView, RunArchiveDetail, RunArchiveChange, Bar, TradeEvent, TestList, Intervals, ConfigItem, InstantIndicator
from v2realbot.utils.utils import AttributeDict, zoneNY, zonePRG, safe_get, dict_replace_value, Store, parse_toml_string, json_serial, is_open_hours, send_to_telegram
from v2realbot.utils.ilog import delete_logs
from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus, TradeStoplossType
@ -32,6 +32,8 @@ from threading import Lock
from v2realbot.common.db import pool, execute_with_retry, row_to_runarchive, row_to_runarchiveview
from sqlite3 import OperationalError, Row
import v2realbot.strategyblocks.indicators.custom as ci
from v2realbot.strategyblocks.inits.init_indicators import initialize_dynamic_indicators
from v2realbot.strategyblocks.indicators.indicators_hub import populate_dynamic_indicators
from v2realbot.interfaces.backtest_interface import BacktestInterface
#from pyinstrument import Profiler
@ -1071,12 +1073,15 @@ def update_archive_detail(id: UUID, archdetail: RunArchiveDetail):
try:
c = conn.cursor()
json_string = json.dumps(archdetail, default=json_serial)
statement = f"UPDATE runner_detail SET data = '{json_string}' WHERE runner_id='{str(id)}'"
res = execute_with_retry(c,statement)
statement = "UPDATE runner_detail SET data = ? WHERE runner_id = ?"
params = (json_string, str(id))
##statement = f"UPDATE runner_detail SET data = '{json_string}' WHERE runner_id='{str(id)}'"
##print(statement)
res = execute_with_retry(cursor=c,statement=statement,params=params)
conn.commit()
finally:
pool.release_connection(conn)
return res.rowcount
return 0, res.rowcount
def insert_archive_detail(archdetail: RunArchiveDetail):
conn = pool.get_connection()
@ -1111,15 +1116,40 @@ def get_testlists():
# endregion
#WIP - possibility to add TOML indicator
# open issues: hodnoty dalsich indikatoru
def preview_indicator_byTOML(id: UUID, toml: str):
#WIP - instant indicators
def preview_indicator_byTOML(id: UUID, indicator: InstantIndicator):
try:
res, toml_parsed = parse_toml_string(toml)
if indicator.name is None:
return (-2, "name is required")
#print("na zacatku", indicator.toml)
tomlino = indicator.toml
jmeno = indicator.name
#print("tomlino",tomlino)
#print("jmeno",jmeno)
# indicator = AttributeDict(**indicator.__dict__)
# print(indicator)
# def format_toml_string(toml_string):
# return f"'''{toml_string.strip()}'''"
# print("before",indicator['toml'])
# indicator['toml'] = format_toml_string(indicator['toml'])
# print(indicator['toml'])
# print("jmeno", str(indicator.name))
# row = f"[stratvars]\n[stratvars.indicators.{str(indicator.name)}]\n"
# print(row, end='')
# row = "[stratvars]\n[stratvars.indicators.{indicator.name}]\n"
# print(row.format(indicator=indicator))
# print(row)
res, toml_parsed = parse_toml_string(tomlino)
if res < 0:
return (-2, "toml invalid")
print("parsed toml", toml_parsed)
#print("parsed toml", toml_parsed)
subtype = safe_get(toml_parsed, 'subtype', False)
if subtype is None:
@ -1133,16 +1163,6 @@ def preview_indicator_byTOML(id: UUID, toml: str):
if res < 0:
return (-2, "no archived runner {id}")
# class RunArchiveDetail(BaseModel):
# id: UUID
# name: str
# bars: dict
# #trades: Optional[dict]
# indicators: List[dict]
# statinds: dict
# trades: List[TradeUpdate]
# ext_data: Optional[dict]
#TODO - conditional udelat podminku
# if value == "conditional":
# conditions = state.vars.indicators[indname]["cp"]["conditions"]
@ -1156,57 +1176,140 @@ def preview_indicator_byTOML(id: UUID, toml: str):
detail = RunArchiveDetail(**val)
#print("toto jsme si dotahnuli", detail.bars)
#pokud tento indikator jiz je v detailu, tak ho odmazeme
if indicator.name in detail.indicators[0]:
del detail.indicators[0][indicator.name]
#new dicts
new_bars = {key: [] for key in detail.bars.keys()}
new_bars = AttributeDict(**new_bars)
new_data = {key: None for key in detail.bars.keys()}
new_data= AttributeDict(**new_data)
new_inds = {key: [] for key in detail.indicators[0].keys()}
new_inds = AttributeDict(**new_inds)
interface = BacktestInterface(symbol="X", bt=None)
state = StrategyState(name="XX", symbol = "X", stratvars = toml, interface=interface)
##dame nastaveni indikatoru do tvaru, ktery stratvars ocekava (pro dynmaicke inicializace)
stratvars = AttributeDict(indicators=AttributeDict(**{jmeno:toml_parsed}))
print("stratvars", stratvars)
state = StrategyState(name="XX", symbol = "X", stratvars = AttributeDict(**stratvars), interface=interface)
#inicializujeme novy indikator v cilovem dict a stavovem inds.
new_inds[indicator.name] = []
new_inds[indicator.name] = []
state.bars = new_bars
state.indicators = new_inds
new_inds["new"] = []
print("delka",len(detail.bars["close"]))
#intitialize indicator mapping - in order to use eval in expression
local_dict_inds = {key: state.indicators[key] for key in state.indicators.keys() if key != "time"}
local_dict_bars = {key: state.bars[key] for key in state.bars.keys() if key != "time"}
state.ind_mapping = {**local_dict_inds, **local_dict_bars}
print("IND MAPPING DONE:", state.ind_mapping)
##intialize dynamic indicators
initialize_dynamic_indicators(state)
# print("subtype")
# function = "ci."+subtype+"."+subtype
# print("funkce", function)
# custom_function = eval(function)
print("subtype")
function = "ci."+subtype+"."+subtype
print("funkce", function)
custom_function = eval(function)
#iterujeme nad bary a on the fly pridavame novou hodnotu do vsech indikatoru a nakonec nad tim spustime indikator
#tak muzeme v toml pouzit i hodnoty ostatnich indikatoru
for i in range(len(detail.bars["close"])):
for key in detail.bars:
state.bars[key].append(detail.bars[key][i])
#naplnime i data aktualne
new_data[key] = state.bars[key][-1]
for key in detail.indicators[0]:
state.indicators[key].append(detail.indicators[0][key][i])
new_inds["new"].append(0)
new_inds[indicator.name].append(0)
try:
res_code, new_val = custom_function(state, custom_params)
if res_code == 0:
new_inds["new"][-1]=new_val
populate_dynamic_indicators(new_data, state)
# res_code, new_val = custom_function(state, custom_params)
# if res_code == 0:
# new_inds[indicator.name][-1]=new_val
except Exception as e:
print(str(e) + format_exc())
print("Done", f"delka {len(new_inds['new'])}", new_inds["new"])
return 0, new_inds["new"]
print("Done - static", f"delka {len(state.indicators[indicator.name])}", state.indicators[indicator.name])
#print("Done", f"delka {len(new_inds[indicator.name])}", new_inds[indicator.name])
new_inds[indicator.name] = state.indicators[indicator.name]
#ukládáme do ArchRunneru
detail.indicators[0][indicator.name] = new_inds[indicator.name]
#do ext dat ukladame jmeno indikatoru (podle toho oznacuje jako zmenene)
#inicializace ext_data a instantindicator pokud neexistuje
if hasattr(detail, "ext_data"):
if "instantindicators" not in detail.ext_data:
detail.ext_data["instantindicators"] = []
else:
setattr(detail, "ext_data", dict(instantindicators=[]))
#pokud tam je tak odebereme
for ind in detail.ext_data["instantindicators"]:
if ind["name"] == indicator.name:
detail.ext_data["instantindicators"].remove(ind)
print("removed old from EXT_DATA")
#a pridame aktualni
detail.ext_data["instantindicators"].append(indicator)
print("added to EXT_DATA")
#updatneme ArchRunner
res, val = update_archive_detail(id, detail)
if res == 0:
print(f"arch runner {id} updated")
return 0, new_inds[indicator.name]
except Exception as e:
print(str(e) + format_exc())
return -2, str(e)
def delete_indicator_byName(id: UUID, indicator: InstantIndicator):
try:
#dotahne runner details
res, val = get_archived_runner_details_byID(id)
if res < 0:
return (-2, "no archived runner {id}")
detail = RunArchiveDetail(**val)
#print("toto jsme si dotahnuli", detail.bars)
#pokud tento indikator je v detailu
if indicator.name in detail.indicators[0]:
del detail.indicators[0][indicator.name]
print("values removed from indicators")
#do ext dat ukladame jmeno indikatoru (podle toho oznacuje jako zmenene)
if hasattr(detail, "ext_data") and "instantindicators" in detail.ext_data:
for ind in detail.ext_data["instantindicators"]:
if ind["name"] == indicator.name:
detail.ext_data["instantindicators"].remove(ind)
print("removed from EXT_DATA")
#updatneme ArchRunner
res, val = update_archive_detail(id, detail)
if res == 0:
print("Archive udpated")
return 0, val
except Exception as e:
print(str(e) + format_exc())
return -2, str(e)
# region CONFIG db services
#TODO vytvorit modul pro dotahovani z pythonu (get_from_config(var_name, def_value) {)- stejne jako v js

View File

@ -11,7 +11,7 @@ import uvicorn
from uuid import UUID
import v2realbot.controller.services as cs
from v2realbot.utils.ilog import get_log_window
from v2realbot.common.model import StrategyInstance, RunnerView, RunRequest, Trade, RunArchive, RunArchiveView, RunArchiveDetail, Bar, RunArchiveChange, TestList, ConfigItem, TomlInput
from v2realbot.common.model import StrategyInstance, RunnerView, RunRequest, Trade, RunArchive, RunArchiveView, RunArchiveDetail, Bar, RunArchiveChange, TestList, ConfigItem, InstantIndicator
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Depends, HTTPException, status, WebSocketException, Cookie, Query
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles
@ -432,15 +432,27 @@ def _delete_archived_runners_byIDs(runner_ids: list[UUID]):
#WIP - TOM indicator preview from frontend
#return indicator value for archived runner
@app.put("/archived_runners/{runner_id}/previewindicator", dependencies=[Depends(api_key_auth)], status_code=status.HTTP_200_OK)
def _preview_indicator_byTOML(runner_id: UUID, toml: TomlInput) -> list[float]:
def _preview_indicator_byTOML(runner_id: UUID, indicator: InstantIndicator) -> list[float]:
#mozna pak pridat name
res, vals = cs.preview_indicator_byTOML(id=runner_id, toml=toml.toml)
res, vals = cs.preview_indicator_byTOML(id=runner_id, indicator=indicator)
if res == 0: return vals
elif res == -1:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Error: {res}:{vals}")
else:
raise HTTPException(status_code=status.HTTP_406_NOT_ACCEPTABLE, detail=f"Error not changed: {res}:{runner_id}:{vals}")
#delete instant indicator from detail
@app.delete("/archived_runners/{runner_id}/previewindicator", dependencies=[Depends(api_key_auth)], status_code=status.HTTP_200_OK)
def _delete_indicator_byName(runner_id: UUID, indicator: InstantIndicator):
#mozna pak pridat name
res, vals = cs.delete_indicator_byName(id=runner_id, indicator=indicator)
if res == 0: return vals
elif res == -1:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Error: {res}:{vals}")
else:
raise HTTPException(status_code=status.HTTP_406_NOT_ACCEPTABLE, detail=f"Error not changed: {res}:{runner_id}:{vals}")
#edit archived runner ("note",..)
@app.patch("/archived_runners/{runner_id}", dependencies=[Depends(api_key_auth)])

View File

@ -747,6 +747,7 @@
<script src="/static/js/utils.js"></script>
<script src="/static/js/instantindicators.js"></script>
<script src="/static/js/archivechart.js"></script>
<script src="/static/js/archivetables.js"></script>
<script src="/static/js/livewebsocket.js"></script>

View File

@ -340,26 +340,45 @@ function chart_indicators(data, visible, offset) {
var cnf = null
//pokud je v nastaveni scale, pouzijeme tu
var scale = null
try {
if (addedInds[key]) {
cnf = addedInds[key]
var instant = null
//console.log(key)
//zkusime zda nejde o instantni indikator z arch runneru
if ((data.ext_data !== null) && (data.ext_data.instantindicators)) {
let instantIndicator = data.ext_data.instantindicators.find(indicator => indicator.name == key);
//console.log("nalezen", key)
if (instantIndicator) {
cnf = instantIndicator.toml
scale = TOML.parse(cnf).scale
instant = 1
}
else
{
}
//pokud nenalezeno, pak bereme standard
//pozor ted nebereme z addedInds
if (!cnf) {
if (stratvars_toml.stratvars.indicators[key]) {
cnf = "#[stratvars.indicators."+key+"]"+TOML.stringify(stratvars_toml.stratvars.indicators[key], {newline: '\n'})
scale = stratvars_toml.stratvars.indicators[key].scale
//cnf = TOML.stringify(stratvars_toml.stratvars.indicators[key], {newline: '\n'})
//a = TOML.parse(cnf)
//console.log("PARSED again",a)
}
}
catch (e) {
//nic
}
// //kontriolujeme v addedInds
// if (addedInds[key]) {
// cnf = addedInds[key]
// scale = TOML.parse(cnf).scale
// instant = 1
// }
// //a az potom bereme normos
// else
// {
// cnf = "#[stratvars.indicators."+key+"]"+TOML.stringify(stratvars_toml.stratvars.indicators[key], {newline: '\n'})
// scale = stratvars_toml.stratvars.indicators[key].scale
// //cnf = TOML.stringify(stratvars_toml.stratvars.indicators[key], {newline: '\n'})
// //a = TOML.parse(cnf)
// //console.log("PARSED again",a)
// }
// }
//initialize indicator and store reference to array
var obj = {name: key, series: null, cnf:cnf, added: ((addedInds[key])?1:null)}
var obj = {name: key, series: null, cnf:cnf, instant: instant}
//start
//console.log(key)
@ -580,7 +599,9 @@ function remove_indicators() {
}
//switch to interval pomocna funkce
function switch_to_interval(interval, data) {
function switch_to_interval(interval, data, extra) {
store_activated_buttons_state(extra);
if (!data) {
window.alert("no data switch to interval")
}
@ -671,7 +692,7 @@ function display_buy_markers(data) {
//xx - ted bude slLine pole
transformed_data["sl_line"].forEach((slRecord, index, array) => {
console.log("uvnitr")
//console.log("uvnitr")
slLine_temp = chart.addLineSeries({
// title: "avgpbuyline",
color: '#e4c76d',

View File

@ -2,7 +2,6 @@
let editor_diff_arch1
let editor_diff_arch2
var archData = null
var addedInds = {}
function refresh_arch_and_callback(row, callback) {
//console.log("entering refresh")
@ -314,129 +313,6 @@ $(document).ready(function () {
}
});
//Kod pro add indicator -dat do arch chart souboru
//modal - delete indicator button
$('#deleteIndicatorButton').click(function () {
window.$('#indicatorModal').modal('hide');
indname = $('#indicatorName').val()
//updatneme globalni promennou obsahujici vsechny arch data
//TBD nebude fungovat az budu mit vic chartů otevřených - předělat
if (archData.indicators[0][indname]) {
delete archData.indicators[0][indname]
delete addedInds[indname]
//get active resolution
const element = document.querySelector('.switcher-active-item');
resolution = element.textContent
//console.log("aktivni rozliseni", resolution)
switch_to_interval(resolution, archData)
}
});
var myModalEl = document.getElementById('indicatorModal')
myModalEl.addEventListener('hidden.bs.modal', function (event) {
close_addind_modal()
})
function close_addind_modal() {
index = $('#indicatorId').val()
const elem = document.getElementById("IND"+index);
if (elem) {
elem.classList.replace('switcher-item-highlighted', 'switcher-item');
}
//vracime pripadny schovany del button
$('#deleteIndicatorButton').show();
window.$('#indicatorModal').modal('hide');
}
//HLAVNI SAVE akce INDICATOR MODAL - ulozi nebo vytvori novy
$('#saveIndicatorButton').click(function () {
indName = $('#indicatorName').val()
if (!indName) {
alert("name musi byt vyplneno")
return
}
index = $('#indicatorId').val()
var elem = document.getElementById("IND"+index);
if (elem) {
//pokud existuje - pak jde bud o edit nebo duplicate - podle jmena
//jmeno je updatnute, jde o duplicate - vytvarime novy index
if (elem.textContent !== $('#indicatorName').val()) {
//alert("duplikujeme")
index_ind++
index = index_ind
}
}
//pokud neexistuje, pak jde o novy index - pouzijeme tento
runner_id = $("#statusArchId").text()
if (!runner_id) {
alert("no arch runner selected")
return
}
// row = archiveRecords.row('.selected').data();
// if (row == undefined) {
// }
store_activated_buttons_state()
//pridame jeste tu aktualni, aby se zobrazila jako aktivni
activatedButtons.push(indName);
//console.log(activatedButtons)
obj = new Object()
obj.runner_id = runner_id
obj.toml = ind_editor.getValue()
jsonString = JSON.stringify(obj);
//console.log("pred odeslanim",jsonString)
//cal rest api
$.ajax({
url:"/archived_runners/"+runner_id+"/previewindicator",
beforeSend: function (xhr) {
xhr.setRequestHeader('X-API-Key',
API_KEY); },
method:"PUT",
contentType: "application/json",
data: jsonString,
success:function(data){
//kod pro update/vytvoreni je zde stejny - updatujeme jen zdrojove dictionary
window.$('#indicatorModal').modal('hide');
//console.log(data)
//indName = $('#indicatorName').val()
//updatneme/vytvorime klic v globalni promennou obsahujici vsechny arch data
//TBD nebude fungovat az budu mit vic chartů otevřených - předělat
archData.indicators[0][indName] = data
//glob promenna obsahujici aktualne pridane indikatory a jejich konfigurace
addedInds[indName] = obj.toml
//get active resolution
const element = document.querySelector('.switcher-active-item');
resolution = element.textContent
//console.log("aktivni rozliseni", resolution)
switch_to_interval(resolution, archData)
},
error: function(xhr, status, error) {
var err = eval("(" + xhr.responseText + ")");
window.alert(JSON.stringify(xhr));
//console.log(JSON.stringify(xhr));
//$('#button_runagain_arch').attr('disabled',false);
}
})
// #indicatorId
// #indicatorName
// #indicatorTOML
//$('#editidarchive').val(row.id);
//$('#editnote').val(row.note);
});
//show button
$('#button_show_arch').click(function () {

View File

@ -0,0 +1,184 @@
//docasne ulozeni aktivovanych buttonu pred reloadem
var activatedButtons = []
//seznam upravenych instant indikatoru a jejich konfigurace
// var addedInds = {}
function store_activated_buttons_state(extra) {
activatedButtons = []
if (extra) {
activatedButtons.push(extra)
}
//ulozime si stav aktivovaných buttonků před změnou - mozna do sluzby
$('#indicatorsButtons .switcher-active-item').each(function() {
activatedButtons.push($(this).text());
});
}
//JQUERY SECTION
$(document).ready(function () {
//modal - delete indicator button
$('#deleteIndicatorButton').click(function () {
indname = $('#indicatorName').val()
runner_id = $("#statusArchId").text()
if (!runner_id) {
alert("no arch runner selected")
return
}
obj = new Object()
obj.runner_id = runner_id
obj.toml = TOML.parse(ind_editor.getValue())
obj.name = indname
jsonString = JSON.stringify(obj);
//console.log("pred odeslanim",jsonString)
//cal rest api
$.ajax({
url:"/archived_runners/"+runner_id+"/previewindicator",
beforeSend: function (xhr) {
xhr.setRequestHeader('X-API-Key',
API_KEY); },
method:"DELETE",
contentType: "application/json",
data: jsonString,
success:function(data){
window.$('#indicatorModal').modal('hide');
//updatneme globalni promennou obsahujici vsechny arch data
//TBD nebude fungovat az budu mit vic chartů otevřených - předělat
//smazeme zaznam o indiaktoru v lokalni kopii ext_data (z nich se pak prekresli indikatory)
if ((archData.ext_data !== null) && (archData.ext_data.instantindicators)) {
let index = archData.ext_data.instantindicators.findIndex(indicator => indicator.name === indname);
if (index !== -1) {
archData.ext_data.instantindicators.splice(index, 1);
}
}
if (archData.indicators[0][indname]) {
delete archData.indicators[0][indname]
//delete addedInds[indname]
//get active resolution
const element = document.querySelector('.switcher-active-item');
resolution = element.textContent
//console.log("aktivni rozliseni", resolution)
switch_to_interval(resolution, archData)
}
},
error: function(xhr, status, error) {
var err = eval("(" + xhr.responseText + ")");
window.alert(JSON.stringify(xhr));
//console.log(JSON.stringify(xhr));
//$('#button_runagain_arch').attr('disabled',false);
}
})
});
var myModalEl = document.getElementById('indicatorModal')
myModalEl.addEventListener('hidden.bs.modal', function (event) {
close_indicator_modal()
})
function close_indicator_modal() {
index = $('#indicatorId').val()
const elem = document.getElementById("IND"+index);
if (elem) {
elem.classList.replace('switcher-item-highlighted', 'switcher-item');
}
//vracime pripadny schovany del button
$('#deleteIndicatorButton').show();
$('#saveIndicatorButton').show();
window.$('#indicatorModal').modal('hide');
}
//HLAVNI SAVE akce INDICATOR MODAL - ulozi nebo vytvori novy
$('#saveIndicatorButton').click(function () {
indName = $('#indicatorName').val()
if (!indName) {
alert("name musi byt vyplneno")
return
}
index = $('#indicatorId').val()
var elem = document.getElementById("IND"+index);
if (elem) {
//pokud existuje - pak jde bud o edit nebo duplicate - podle jmena
//jmeno je updatnute, jde o duplicate - vytvarime novy index
if (elem.textContent !== $('#indicatorName').val()) {
//alert("duplikujeme")
index_ind++
index = index_ind
}
}
//pokud neexistuje, pak jde o novy index - pouzijeme tento
runner_id = $("#statusArchId").text()
if (!runner_id) {
alert("no arch runner selected")
return
}
// store_activated_buttons_state()
// //pridame jeste tu aktualni, aby se zobrazila jako aktivni
// activatedButtons.push(indName);
console.log(activatedButtons)
obj = new Object()
//obj.runner_id = runner_id
obj.name = indName
obj.toml = ind_editor.getValue()
jsonString = JSON.stringify(obj);
//console.log("pred odeslanim",jsonString)
//cal rest api
$.ajax({
url:"/archived_runners/"+runner_id+"/previewindicator",
beforeSend: function (xhr) {
xhr.setRequestHeader('X-API-Key',
API_KEY); },
method:"PUT",
contentType: "application/json",
data: jsonString,
success:function(data){
//kod pro update/vytvoreni je zde stejny - updatujeme jen zdrojove dictionary
window.$('#indicatorModal').modal('hide');
//console.log(data)
//indName = $('#indicatorName').val()
//updatneme/vytvorime klic v globalni promennou obsahujici vsechny arch data
//TBD nebude fungovat az budu mit vic chartů otevřených - předělat
archData.indicators[0][indName] = data
//pridame pripadne upatneme v ext_data
//smazeme zaznam o indiaktoru v lokalni kopii ext_data (z nich se pak prekresli indikatory)
if ((archData.ext_data !== null) && (archData.ext_data.instantindicators)) {
let index = archData.ext_data.instantindicators.findIndex(indicator => indicator.name === indName);
if (index !== -1) {
archData.ext_data.instantindicators.splice(index, 1);
}
archData.ext_data.instantindicators.push(obj)
}
//neexistuje instantindicators - vytvorime jej a vlozime prvni objekt
else if ((archData.ext_data !== null) && (!archData.ext_data.instantindicators)) {
//a pridame tamtez novy zaznam
archData.ext_data["instantindicators"] =[obj]
}
//glob promenna obsahujici aktualne pridane indikatory a jejich konfigurace
//addedInds[indName] = obj.toml
//get active resolution
const element = document.querySelector('.switcher-active-item');
resolution = element.textContent
//console.log("aktivni rozliseni", resolution)
//vykreslime a pridavame jeste nazev indikatoru, ktery se ma vykreslit do aktivnich
switch_to_interval(resolution, archData, indName)
},
error: function(xhr, status, error) {
var err = eval("(" + xhr.responseText + ")");
window.alert(JSON.stringify(xhr));
//console.log(JSON.stringify(xhr));
//$('#button_runagain_arch').attr('disabled',false);
}
})
});
});

View File

@ -13,7 +13,6 @@ var candlestickSeries = null
var volumeSeries = null
var vwapSeries = null
var statusBarConfig = JSON.parse(localStorage.getItem("statusBarConfig"));
var activatedButtons = []
if (statusBarConfig == null) {
statusBarConfig = {}
}
@ -58,14 +57,6 @@ var indConfig_default = [ {name: "ema", titlevisible: false, embed: true, displa
{name: "sec_price", titlevisible: true, embed: true, display: true, priceScaleId: "right", lastValueVisible: false},]
//console.log(JSON.stringify(indConfig_default, null,null, 2))
function store_activated_buttons_state() {
activatedButtons = []
//ulozime si stav aktivovaných buttonků před změnou - mozna do sluzby
$('#indicatorsButtons .switcher-active-item').each(function() {
activatedButtons.push($(this).text());
});
}
function initialize_statusheader() {
var rows = 2;
@ -351,7 +342,7 @@ function create_indicator_button(item, index, def) {
itemEl.title = item.cnf
itemEl.style.color = item.series.options().color;
//pokud jde o pridanou on the fly - vybarvime jinak
if (item.added) {
if (item.instant) {
itemEl.style.outline = "solid 1px"
}
itemEl.classList.add('switcher-item');
@ -411,11 +402,35 @@ function onResetClicked() {
visible: vis });
}
})
store_activated_buttons_state();
}
function generateIndicators(e) {
alert("stratvars generated to clipboard from selected indicators")
store_activated_buttons_state();
ind_tom = ""
indList.forEach(function (item, index) {
if (activatedButtons.includes(item.name)) {
console.log(item)
ind_tom += "\n[stratvars.indicators."+item.name+"]\n" + item.cnf
}
});
if (ind_editor) {
ind_editor.dispose()
}
require(["vs/editor/editor.main"], () => {
ind_editor = monaco.editor.create(document.getElementById('indicatorTOML_editor'), {
value: ind_tom,
language: 'toml',
theme: 'tomlTheme-dark',
automaticLayout: true
});
});
$('#deleteIndicatorButton').hide();
$('#saveIndicatorButton').hide();
window.$('#indicatorModal').modal('show');
}
//editace indikatoru, vcetne vytvoreni noveho
@ -509,6 +524,7 @@ function populate_indicator_buttons(def) {
//console.log("activatedButtons", activatedButtons)
//console.log("obsahuje item.name", activatedButtons.includes(item.name), item.name)
//pokud existuje v aktivnich pak
//console.log("vytvarime button",item.name,activatedButtons)
if ((activatedButtons) && (activatedButtons.includes(item.name))) {
active = true
}

View File

@ -24,13 +24,19 @@ def populate_dynamic_RSI_indicator(data, state: StrategyState, name):
req_source = safe_get(options, 'source', 'vwap')
rsi_length = int(safe_get(options, "length",14))
rsi_MA_length = safe_get(options, "MA_length", None)
start = safe_get(options, "start","linear") #linear/sharp
if on_confirmed_only is False or (on_confirmed_only is True and data['confirmed']==1):
try:
#source = state.bars[req_source]
source = get_source_series(state, req_source)
#cekame na dostatek dat
if len(source) > rsi_length:
delka = len(source)
if delka > rsi_length or start == "linear":
if delka <= rsi_length and start == "linear":
rsi_length = delka
rsi_res = rsi(source, rsi_length)
rsi_value = round(rsi_res[-1],4)
state.indicators[name][-1]=rsi_value

View File

@ -54,5 +54,6 @@ def conditional(state, params):
return 0, 0
except Exception as e:
printanyway(str(e)+format_exc())
return -2, str(e)+format_exc()

View File

@ -17,17 +17,16 @@ def expression(state: StrategyState, params):
if operation is None :
return -2, "required param missing"
state.ilog(lvl=1,e=f"BEFORE {funcName} {operation=}", **params)
state.ilog(lvl=0,e=f"BEFORE {funcName} {operation=}", **params)
#pro zacatek eval
val = eval(operation, {'state': state}, state.ind_mapping)
val = eval(operation, {'state': state, 'np': np}, state.ind_mapping)
if not np.isfinite(val):
val = 0
#val = ne.evaluate(operation, state.ind_mapping)
state.ilog(lvl=1,e=f"AFTER {funcName} {operation=} res:{val}", **params)
state.ilog(lvl=1,e=f"IND {funcName} {operation=} res:{val}", **params)
return 0, val

View File

@ -16,6 +16,7 @@ def ma(state, params):
type = safe_get(params, "type", "ema")
source = safe_get(params, "source", None)
lookback = safe_get(params, "lookback",14)
start = safe_get(params, "start","linear") #linear/sharp
#lookback muze byt odkaz na indikator, pak berem jeho hodnotu
lookback = int(value_or_indicator(state, lookback))
@ -23,8 +24,11 @@ def ma(state, params):
source_series = get_source_series(state, source)
#pokud je mene elementu, pracujeme s tim co je
if len(source_series) > lookback:
source_series = source_series[-lookback:]
akt_pocet = len(source_series)
if akt_pocet < lookback and start == "linear":
lookback = akt_pocet
#source_series = source_series[-lookback:]
type = "mi."+type
ma_function = eval(type)

View File

@ -20,6 +20,7 @@ from traceback import format_exc
def initialize_dynamic_indicators(state):
#pro vsechny indikatory, ktere maji ve svych stratvars TYPE inicializujeme
##ßprintanyway(state.vars, state)
dict_copy = state.vars.indicators.copy()
for indname, indsettings in dict_copy.items():
for option,value in list(indsettings.items()):

View File

@ -9,7 +9,7 @@ import decimal
from v2realbot.enums.enums import RecordType, Mode, StartBarAlign
import pickle
import os
from v2realbot.common.model import StrategyInstance, Runner, RunArchive, RunArchiveDetail, Intervals, SLHistory
from v2realbot.common.model import StrategyInstance, Runner, RunArchive, RunArchiveDetail, Intervals, SLHistory, InstantIndicator
from v2realbot.common.PrescribedTradeModel import Trade, TradeDirection, TradeStatus, TradeStoplossType
from typing import List
import tomli
@ -337,6 +337,7 @@ def json_serial(obj):
RunArchiveDetail: lambda obj: obj.__dict__,
Intervals: lambda obj: obj.__dict__,
SLHistory: lambda obj: obj.__dict__,
InstantIndicator: lambda obj: obj.__dict__,
}
serializer = type_map.get(type(obj))
@ -354,29 +355,9 @@ def json_serial_old(obj):
if isinstance(obj, (datetime, date)):
return obj.timestamp()
if isinstance(obj, UUID):
if isinstance(obj, UUID) or isinstance(obj, Enum) or isinstance(obj, np.int64):
return str(obj)
if isinstance(obj, Enum):
return str(obj)
if isinstance(obj, np.int64):
return int(obj)
if type(obj) is Order:
return obj.__dict__
if type(obj) is TradeUpdate:
return obj.__dict__
if type(obj) is btOrder:
return obj.__dict__
if type(obj) is btTradeUpdate:
return obj.__dict__
if type(obj) is RunArchive:
return obj.__dict__
if type(obj) is Trade:
return obj.__dict__
if type(obj) is RunArchiveDetail:
return obj.__dict__
if type(obj) is Intervals:
return obj.__dict__
if type(obj) is SLHistory:
if type(obj) in [Order, TradeUpdate, btOrder, btTradeUpdate, RunArchive, Trade, RunArchiveDetail, Intervals, SLHistory, InstantIndicator]:
return obj.__dict__
raise TypeError (str(obj)+"Type %s not serializable" % type(obj))