finalni instant indikatory + save do arch
This commit is contained in:
@ -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"
|
||||
on_confirmed_only = true
|
||||
cp.source = "vwap"
|
||||
cp.ref_source = "volume"
|
||||
cp.lookback = 50
|
||||
#[stratvars.indicators.cross]
|
||||
type = 'custom'
|
||||
subtype = 'conditional'
|
||||
on_confirmed_only = true
|
||||
[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)
|
||||
|
||||
@ -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}")
|
||||
|
||||
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)])
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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',
|
||||
|
||||
@ -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 () {
|
||||
|
||||
|
||||
184
v2realbot/static/js/instantindicators.js
Normal file
184
v2realbot/static/js/instantindicators.js
Normal 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);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
});
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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()
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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()):
|
||||
|
||||
@ -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))
|
||||
|
||||
Reference in New Issue
Block a user