This commit is contained in:
David Brazda
2023-05-08 18:34:13 +02:00
parent 45c356c1df
commit 1cdfa803b2
12 changed files with 294 additions and 167 deletions

31
testy/testDict.py Normal file
View File

@ -0,0 +1,31 @@
from v2realbot.utils.utils import AttributeDict
indicators = AttributeDict(time=[])
for key,value in indicators.items():
if key != "time":
indicators[key].append(0)
#as indicators are stored vector based, time is populated for each iteration
def populate_indicator_time(self, item):
if self.rectype == RecordType.BAR:
#jako cas indikatorů pridavame cas baru, jejich hodnoty se naplni v nextu
self.state.indicators['time'].append(item['time'])
elif self.rectype == RecordType.TRADE:
pass
elif self.rectype == RecordType.CBAR:
#novy vzdy pridame
if self.nextnew:
self.state.indicators['time'].append(item['time'])
self.append_bar(self.state.bars,item)
self.nextnew = 0
#nasledujici updatneme, po potvrzeni, nasleduje novy bar
else:
if item['confirmed'] == 0:
self.state.indicators['time'][-1]=item['time']
self.replace_prev_bar(self.state.bars,item)
#confirmed
else:
self.state.indicators['time'][-1]=item['time']
self.replace_prev_bar(self.state.bars,item)
self.nextnew = 1

View File

@ -251,7 +251,7 @@ def next(data, state: StrategyState):
#kvuli spravnemu zobrazovani na gui #kvuli spravnemu zobrazovani na gui
state.indicators.slope.append(0) state.indicators.slope.append(0)
state.indicators.slopeMA.append(0) state.indicators.slopeMA.append(0)
state.ilog(e="Slope - not enough data", slope_lookback=slope_lookback) state.ilog(e="Slope - not enough data", slope_lookback=slope_lookback, slope=state.indicators.slope, slopeMA=state.indicators.slopeMA)
except Exception as e: except Exception as e:
print("Exception in NEXT Indicator section", str(e)) print("Exception in NEXT Indicator section", str(e))

View File

@ -543,8 +543,8 @@ def get_alpaca_history_bars(symbol: str, datetime_object_from: datetime, datetim
#ohlcvList = {} #ohlcvList = {}
#bars = {} #bars = {}
#bars.data[symbol]
return 0, bars.data[symbol] return 0, result
except Exception as e: except Exception as e:
return -2, str(e) return -2, str(e)

View File

@ -12,6 +12,8 @@
<link rel="manifest" href="/static/site.webmanifest"> <link rel="manifest" href="/static/site.webmanifest">
<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">
@ -38,7 +40,7 @@
<div id="main" class="mainConteiner flex-container content"> <div id="main" class="mainConteiner flex-container content">
<div id="chartContainer" class="flex-items"> <div id="chartContainer" class="flex-items">
<label data-bs-toggle="collapse" data-bs-target="#chartContainerInner" aria-expanded="true"> <label data-bs-toggle="collapse" data-bs-target="#chartContainerInner" aria-expanded="true">
<h4><span class="badge secondary-bg">Chart</span></h4> <h4>Chart</h4>
</label> </label>
<div>Status: <span id="status">Not connected</span></div> <div>Status: <span id="status">Not connected</span></div>
<div id="chartContainerInner" class="collapse"> <div id="chartContainerInner" class="collapse">
@ -75,7 +77,7 @@
<div id="hist-trades" class="flex-items"> <div id="hist-trades" class="flex-items">
<div id="form-trades"> <div id="form-trades">
<label data-bs-toggle="collapse" data-bs-target="#trades-data"> <label data-bs-toggle="collapse" data-bs-target="#trades-data">
<h4><span class="badge secondary-bg">Trade History</span></h4> <h4>Trade History</h4>
</label> </label>
<label>Timestamp: <input type="text" id="trade-timestamp" autocomplete="off"/></label> <label>Timestamp: <input type="text" id="trade-timestamp" autocomplete="off"/></label>
<label>SYM: <input type="text" id="trade-symbol" autocomplete="off"/></label> <label>SYM: <input type="text" id="trade-symbol" autocomplete="off"/></label>
@ -90,7 +92,7 @@
</div> </div>
<div id="runner-table" class="flex-items"> <div id="runner-table" class="flex-items">
<label data-bs-toggle="collapse" data-bs-target="#runner-table-inner"> <label data-bs-toggle="collapse" data-bs-target="#runner-table-inner">
<h4><span class="badge secondary-bg">Running Strategies</span></h4> <h4>Running Strategies</h4>
</label> </label>
<div id="runner-table-inner" class="collapse show" style="width:70%"> <div id="runner-table-inner" class="collapse show" style="width:70%">
<div id="controls"> <div id="controls">
@ -147,7 +149,7 @@
<div id="archive-table" class="flex-items"> <div id="archive-table" class="flex-items">
<label data-bs-toggle="collapse" data-bs-target="#archive-table-inner"> <label data-bs-toggle="collapse" data-bs-target="#archive-table-inner">
<h4><span class="badge secondary-bg">Past Runs</span></h4> <h4>Past Runs</h4>
</label> </label>
<div id="archive-table-inner" class="collapse show" style="width:70%"> <div id="archive-table-inner" class="collapse show" style="width:70%">
<!-- <div id="archive-chart"> <!-- <div id="archive-chart">
@ -243,7 +245,7 @@
</div> </div>
<div id="stratin-table" class="flex-items"> <div id="stratin-table" class="flex-items">
<label data-bs-toggle="collapse" data-bs-target="#stratin-table-inner"> <label data-bs-toggle="collapse" data-bs-target="#stratin-table-inner">
<h4><span class="badge secondary-bg">Strategies</span></h4> <h4>Strategies</h4>
</label> </label>
<div id="stratin-table-inner" class="collapse show" style="width:70%"> <div id="stratin-table-inner" class="collapse show" style="width:70%">
<button id="button_add" class="btn btn-outline-success btn-sm">Add</button> <button id="button_add" class="btn btn-outline-success btn-sm">Add</button>
@ -269,8 +271,8 @@
<th>add_data</th> <th>add_data</th>
<th>note</th> <th>note</th>
<th>history</th> <th>history</th>
<th></th> <th>status</th>
<th></th> <!-- <th></th> -->
</tr> </tr>
</thead> </thead>
<tbody></tbody> <tbody></tbody>
@ -456,7 +458,7 @@
</div> </div>
<div id="configContainer" class="flex-items"> <div id="configContainer" class="flex-items">
<label data-bs-toggle="collapse" data-bs-target="#configInner" aria-expanded="true"> <label data-bs-toggle="collapse" data-bs-target="#configInner" aria-expanded="true">
<h4><span class="badge secondary-bg">Config</span></h4> <h4>Config</h4>
</label> </label>
<div id="configInner" class="collapse show"> <div id="configInner" class="collapse show">
config options config options

View File

@ -90,7 +90,7 @@ function transform_data(data) {
marker["time"] = timestamp; marker["time"] = timestamp;
// marker["position"] = (trade.order.side == "buy") ? "belowBar" : "aboveBar" // marker["position"] = (trade.order.side == "buy") ? "belowBar" : "aboveBar"
marker["position"] = (trade.order.side == "buy") ? "inBar" : "aboveBar" marker["position"] = (trade.order.side == "buy") ? "inBar" : "aboveBar"
marker["color"] = (trade.order.side == "buy") ? "#cfcbc2" : "red" marker["color"] = (trade.order.side == "buy") ? "#37cade" : "red"
//marker["shape"] = (trade.order.side == "buy") ? "arrowUp" : "arrowDown" //marker["shape"] = (trade.order.side == "buy") ? "arrowUp" : "arrowDown"
marker["shape"] = (trade.order.side == "buy") ? "circle" : "arrowDown" marker["shape"] = (trade.order.side == "buy") ? "circle" : "arrowDown"
//marker["text"] = trade.qty + "/" + trade.price //marker["text"] = trade.qty + "/" + trade.price
@ -177,6 +177,7 @@ function chart_archived_run(archRecord, data, oneMinuteBars) {
if (chart !== null) { if (chart !== null) {
chart.remove() chart.remove()
clear_status_header() clear_status_header()
indList = [];
if (toolTip !== null) { if (toolTip !== null) {
toolTip.style.display = 'none'; toolTip.style.display = 'none';
} }
@ -252,6 +253,8 @@ function chart_archived_run(archRecord, data, oneMinuteBars) {
intitialize_candles() intitialize_candles()
candlestickSeries.setData(AllCandleSeriesesData.get(interval)); candlestickSeries.setData(AllCandleSeriesesData.get(interval));
display_buy_markers();
if (last_range) { if (last_range) {
chart.timeScale().setVisibleRange(last_range); chart.timeScale().setVisibleRange(last_range);
} }
@ -433,8 +436,15 @@ function chart_archived_run(archRecord, data, oneMinuteBars) {
} }
} }
//gets indicators from archived data and displays them on the chart //displays (redraws) buy markers
function display_buy_markers() {
if (avgBuyLine !== null) {
chart.removeSeries(avgBuyLine)
}
if (markersLine !== null) {
chart.removeSeries(markersLine)
}
console.log("avgp_buy_line",transformed_data["avgp_buy_line"]) console.log("avgp_buy_line",transformed_data["avgp_buy_line"])
console.log("avgp_markers",transformed_data["avgp_markers"]) console.log("avgp_markers",transformed_data["avgp_markers"])
@ -472,48 +482,9 @@ function chart_archived_run(archRecord, data, oneMinuteBars) {
lastValueVisible: false lastValueVisible: false
}); });
try {
markersLine.setData(transformed_data["markers_line"]); markersLine.setData(transformed_data["markers_line"]);
}
catch (error) {
console.log("markersLine")
}
markersLine.setMarkers(transformed_data["markers"]) markersLine.setMarkers(transformed_data["markers"])
//TBD dynamicky
//pokud je nazev atributu X_candles vytvorit candles
//pokud je objekt Y_line pak vytvorit lajnu
//pokud je objekt Z_markers pak vytvorit markers
//pokud je Z = X nebo Y, pak markers dat na danou lajnu (priklad vvwap_line, avgp_line, avgp_markers)
//udelat si nahodny vyber barev z listu
//DO BUDOUCNA MARKERS
// chart.subscribeCrosshairMove(param => {
// console.log(param.hoveredObjectId);
// });
//TODO onlick zkopirovat timestamp param.time
// chart.subscribeClick(param => {
// $('#trade-timestamp').val(param.time)
// //alert(JSON.safeStringify(param))
// //console.log(param.hoveredObjectId);
// });
//TODO
// - legend
// - identifikatory
// - volume
//chart.subscribeCrosshairMove(param => { //chart.subscribeCrosshairMove(param => {
chart.subscribeCrosshairMove(param => { chart.subscribeCrosshairMove(param => {
//LEGEND SECTIOIN //LEGEND SECTIOIN
@ -577,6 +548,7 @@ function chart_archived_run(archRecord, data, oneMinuteBars) {
//}); //});
} }
}); });
}
chart.subscribeClick(param => { chart.subscribeClick(param => {
$('#trade-timestamp').val(param.time) $('#trade-timestamp').val(param.time)
@ -638,7 +610,7 @@ function chart_archived_run(archRecord, data, oneMinuteBars) {
//add status //add status
$("#statusRegime").text("ARCHIVED RUN") $("#statusRegime").text("PAST RUN: "+archRecord.id)
$("#statusName").text(archRecord.name) $("#statusName").text(archRecord.name)
$("#statusMode").text(archRecord.mode) $("#statusMode").text(archRecord.mode)
$("#statusAccount").text(archRecord.account) $("#statusAccount").text(archRecord.account)

View File

@ -205,6 +205,55 @@ var archiveRecords =
return format_date(data, true) return format_date(data, true)
}, },
}, },
{
targets: [2],
render: function ( data, type, row ) {
return '<div class="tdname" title="'+data+'">'+data+'</i>'
},
},
{
targets: [4],
render: function ( data, type, row ) {
return '<div class="tdnote" title="'+data+'">'+data+'</i>'
},
},
{
targets: [11],
render: function ( data, type, row ) {
//if ilog_save true
if (data) {
return '<span class="material-symbols-outlined">done_outline</span>'
}
else {
return null
}
},
},
{
targets: [8],
render: function ( data, type, row ) {
//if ilog_save true
if (data == "ACCOUNT1") {
res="ACC1"
}
else if (data == "ACCOUNT2") {
res="ACC2"
}
else { res=data}
return res
},
},
{
targets: [7],
render: function ( data, type, row ) {
//if ilog_save true
if (data == "backtest") {
res="bt"
}
else { res=data}
return res
},
}
], ],
order: [[6, 'desc']], order: [[6, 'desc']],
// paging: true, // paging: true,
@ -217,3 +266,6 @@ var archiveRecords =
// } // }
//} //}
} ); } );

View File

@ -6,19 +6,19 @@ function store_api_key(event) {
} }
function get_status(id) { function get_status(id) {
var status = "stopped" var status = ""
runnerRecords.rows().iterator('row', function ( context, index ) { runnerRecords.rows().iterator('row', function ( context, index ) {
var data = this.row(index).data(); var data = this.row(index).data();
//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 = data.run_mode} if ((data.run_mode) == "backtest") { 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 = "running | "+ status_detail status = '<span class="material-symbols-outlined">play_circle</span>'+status_detail
} }
else { else {
status = "paused | "+ status_detail status = '<span class="material-symbols-outlined">pause_circle</span>'+ status_detail
}} }}
//window.alert("found") } //window.alert("found") }
}); });
@ -423,7 +423,7 @@ var stratinRecords =
targets: 12, targets: 12,
render: function ( data, type, row ) { render: function ( data, type, row ) {
var status = get_status(data) var status = get_status(data)
return '<i class="fas fa-check-circle">'+status+'</i>' return status
}, },
}, },
{ {

View File

@ -32,11 +32,13 @@ legendlist.appendChild(firstRow);
function update_chart_legend(param) { function update_chart_legend(param) {
function name(val) { function name(val, color = null) {
return '<div class="legendItemName">' + val + '</>' color = (color)?' style="color: '+ color + ';"' : "";
return '<div class="legendItemName" ' + color + '>' + val + '</>'
} }
function val(val) { function val(val, color = null) {
return '<div class="legendItemValue">' + val + '</>' color = (color)?' style="color: '+ color + ';"' : "";
return '<div class="legendItemValue" ' + color + '>' + val + '</>'
} }
if (param.time) { if (param.time) {
@ -44,24 +46,29 @@ function update_chart_legend(param) {
//BASIC INDICATORS //BASIC INDICATORS
const bars = param.seriesData.get(candlestickSeries); const bars = param.seriesData.get(candlestickSeries);
if (bars !== undefined) { if (bars !== undefined) {
firstRow.innerHTML += name("O") + val(bars.open) + name("H") + val(bars.high) + name("L") + val(bars.low) + name("C") + val(bars.close) //console.log(JSON.stringify(candlestickSeries.options()))
var color = candlestickSeries.options().upColor;
firstRow.innerHTML += name("O", color) + val(bars.open) + name("H", color) + val(bars.high) + name("L", color) + val(bars.low) + name("C") + val(bars.close)
} }
const volumes = param.seriesData.get(volumeSeries); const volumes = param.seriesData.get(volumeSeries);
if (volumes !== undefined) { if (volumes !== undefined) {
firstRow.innerHTML += name("Vol") +val(volumes.value) var color = volumeSeries.options().color;
firstRow.innerHTML += name("Vol", color) +val(volumes.value)
} }
const data = param.seriesData.get(vwapSeries); const data = param.seriesData.get(vwapSeries);
if (data !== undefined) { if (data !== undefined) {
var color = vwapSeries.options().color;
const vwap = data.value !== undefined ? data.value : data.close; const vwap = data.value !== undefined ? data.value : data.close;
firstRow.innerHTML += name('vwap') + val(vwap.toFixed(2)) firstRow.innerHTML += name('vwap', color) + val(vwap.toFixed(2))
} }
//ADDITIONAL CUSTOM INDICATORS //ADDITIONAL CUSTOM INDICATORS
//iterate of custom indicators dictionary to get values of custom lines //iterate of custom indicators dictionary to get values of custom lines
// var customIndicator = {name: key, series: null} // var customIndicator = {name: key, series: null}
indList.forEach(function (item) { indList.forEach(function (item) {
var ind = param.seriesData.get(item.series) var ind = param.seriesData.get(item.series)
if (ind !== undefined) { firstRow.innerHTML += name(item.name) + val(ind.value.toFixed(3))} var color = item.series.options().color;
if (ind !== undefined) { firstRow.innerHTML += name(item.name, color) + val(ind.value.toFixed(3), color)}
}); });
} }
else { else {

View File

@ -1,17 +1,19 @@
/* :root { /* :root {
--dt-row-selected: 18, 143, 175; --dt-row-selected: 18, 143, 175;
--dt-row-selected: 140,142,141;
} */ } */
:root { :root {
--dt-row-selected: 140,142,141; --dt-row-selected: 56,95,126;
--dt-row-selected-text: 173,181,189;
} }
[data-bs-theme=dark] { [data-bs-theme=dark] {
color-scheme: dark; color-scheme: dark;
--bs-body-color: #adb5bd; --bs-body-color: #787b86;
--bs-body-color-rgb: 173,181,189; --bs-body-color-rgb: 173,181,189;
--bs-body-bg: #2a2e39; --bs-body-bg: #2a2e39;
--bs-body-bg-rgb: 33,37,41; --bs-body-bg-rgb: 33,37,41;
--bs-emphasis-color: #fff; --bs-emphasis-color: #adb5bd;
--bs-emphasis-color-rgb: 255,255,255; --bs-emphasis-color-rgb: 255,255,255;
--bs-secondary-color: rgba(173, 181, 189, 0.75); --bs-secondary-color: rgba(173, 181, 189, 0.75);
--bs-secondary-color-rgb: 173,181,189; --bs-secondary-color-rgb: 173,181,189;
@ -58,6 +60,23 @@
--bs-form-invalid-border-color: #ea868f; --bs-form-invalid-border-color: #ea868f;
} }
.form-label {
margin-top: 0.5em;
color: var(--bs-emphasis-color);
}
.form-check {
display: block;
min-height: 2.5rem;
padding-left: 1.5em;
margin-left: 0.25rem;
}
.h4, h4 {
font-size: 1.4rem;
color: var(--bs-emphasis-color);
font-weight: 200;
}
tbody, td, tfoot, th, thead, tr { tbody, td, tfoot, th, thead, tr {
border-color: #7d7d8a; border-color: #7d7d8a;
border-style: solid; border-style: solid;
@ -77,6 +96,32 @@ table.dataTable thead th, table.dataTable thead td, table.dataTable tfoot th, ta
color: #787b86; color: #787b86;
} }
table.dataTable thead>tr>th.sorting, table.dataTable thead>tr>th.sorting_asc, table.dataTable thead>tr>th.sorting_desc, table.dataTable thead>tr>th.sorting_asc_disabled, table.dataTable thead>tr>th.sorting_desc_disabled, table.dataTable thead>tr>td.sorting, table.dataTable thead>tr>td.sorting_asc, table.dataTable thead>tr>td.sorting_desc, table.dataTable thead>tr>td.sorting_asc_disabled, table.dataTable thead>tr>td.sorting_desc_disabled {
cursor: pointer;
position: relative;
padding-right: 10px;
font-size: xx-small;
}
table.dataTable thead>tr>th.sorting:before, table.dataTable thead>tr>th.sorting:after, table.dataTable thead>tr>th.sorting_asc:before, table.dataTable thead>tr>th.sorting_asc:after, table.dataTable thead>tr>th.sorting_desc:before, table.dataTable thead>tr>th.sorting_desc:after, table.dataTable thead>tr>th.sorting_asc_disabled:before, table.dataTable thead>tr>th.sorting_asc_disabled:after, table.dataTable thead>tr>th.sorting_desc_disabled:before, table.dataTable thead>tr>th.sorting_desc_disabled:after, table.dataTable thead>tr>td.sorting:before, table.dataTable thead>tr>td.sorting:after, table.dataTable thead>tr>td.sorting_asc:before, table.dataTable thead>tr>td.sorting_asc:after, table.dataTable thead>tr>td.sorting_desc:before, table.dataTable thead>tr>td.sorting_desc:after, table.dataTable thead>tr>td.sorting_asc_disabled:before, table.dataTable thead>tr>td.sorting_asc_disabled:after, table.dataTable thead>tr>td.sorting_desc_disabled:before, table.dataTable thead>tr>td.sorting_desc_disabled:after {
position: absolute;
display: block;
opacity: 0.525;
right: 4px;
line-height: 9px;
font-size: 0.8em;
}
table.dataTable thead>tr>th.sorting_asc:before, table.dataTable thead>tr>th.sorting_desc:after, table.dataTable thead>tr>td.sorting_asc:before, table.dataTable thead>tr>td.sorting_desc:after {
opacity: 1;
}
.tdnote {
width: 188px;
}
.tdname {
width: 140px;
}
.secondary-bg { .secondary-bg {
--bs-bg-opacity: 1; --bs-bg-opacity: 1;
background-color: #414749; background-color: #414749;
@ -101,6 +146,8 @@ table.dataTable thead th, table.dataTable thead td, table.dataTable tfoot th, ta
--bs-gradient: none; --bs-gradient: none;
} }
/* .btn-outline-success { /* .btn-outline-success {
--bs-btn-color: #316164; --bs-btn-color: #316164;
--bs-btn-border-color: #247e85; --bs-btn-border-color: #247e85;
@ -177,7 +224,7 @@ html {
z-index: 1; z-index: 1;
font-size: 12px; font-size: 12px;
line-height: 18px; line-height: 18px;
font-weight: 300; font-weight: 400;
} }
.legendItemName { .legendItemName {
@ -260,7 +307,7 @@ pre {
} }
.highlighted { .highlighted {
font-weight: bold; color: var(--bs-emphasis-color);
} }
.switcher { .switcher {
@ -279,7 +326,7 @@ pre {
padding: 6px 8px; padding: 6px 8px;
font-size: 14px; font-size: 14px;
color: #262b3e; color: #262b3e;
background-color: transparent; background-color: #818581;
margin-right: 8px; margin-right: 8px;
border: none; border: none;
border-radius: 4px; border-radius: 4px;
@ -300,3 +347,11 @@ pre {
.switcher-active-item:hover { .switcher-active-item:hover {
background-color: #e1eff9; background-color: #e1eff9;
} }
.material-symbols-outlined {
font-variation-settings:
'FILL' 0,
'wght' 300,
'GRAD' 0,
'opsz' 24
}

View File

@ -224,7 +224,15 @@ class Strategy:
self.before_iteration() self.before_iteration()
ted = datetime.fromtimestamp(self.state.time).astimezone(zoneNY) ted = datetime.fromtimestamp(self.state.time).astimezone(zoneNY)
if is_open_rush(ted, self.open_rush) or is_close_rush(ted, self.close_rush): if is_open_rush(ted, self.open_rush) or is_close_rush(ted, self.close_rush):
print("Rush hour - skipping") #self.state.ilog(e="Rush hour - skipping")
#identifikatory jsou ulozeny vektorove, tzn. kdyz nejdeme dovnitr iterace(tak nepotrebujeme prazdny cas pro tuto iteraci)
#hodnoty time a identifikatoru musi byt stejne
#TBD pripdane predelat a dodelat pro CBARy az je budu pouzivat
if self.rectype == RecordType.BAR:
self.state.indicators['time'].pop()
elif self.rectype == RecordType.CBAR:
print("RUSH skipping NOT IMPLEMENTED for CBARs yet")
else: else:
self.next(item, self.state) self.next(item, self.state)
self.after_iteration(item) self.after_iteration(item)