Nekto Finkelmaer
Nekto Finkelmaer личный блог
22 января 2023, 14:46

ТС "Игра теней". Завязка.

ТС «Игра теней». Завязка.

Описание системы здесь​ smart-lab.ru/mobile/topic/872068/

Простыми словами:
При движении цены в одном направлении на пол-процента вероятность движения еще на одну десятую составляет 80%
При этом вероятность возврата цены к открытию составляет 20%

В публикации при расчете доходности системы была допущена ошибка, да простят меня Гаусс, Лейбниц и Стендаль, зато похвалит Росстат.
На скажу что она случайна, однако хорошо, что никто не заметил, застыдили б...

Сегодня я расскажу как увеличить доходность системы простой математикой.

Напоминаю расчет складывается из вероятности движения цены в одном направлении 80% и дополнительном движении цены еще на 0,1% также 80%.
В формуле складывается вероятность обоих событий, однако включать в формулу вероятность свершившегося события, мягко говоря не логично.

Открытие позиции происходит только при движении цены на 0,5%. Таким образом с вероятностью 80% движение цены принесет нам одну десятую процента, а не 64 как было указано.

Годовая доходность системы при данных показателях составляет 120% (200 дней 0,8% плюс, 50% дней 0,8% минус при использовании плеча срочного рынка, симметричный тейк/стоп).

На этом хорошие новости закончились.

При использовании симметричного тейк/стопа добавляются равновероятные события.
Так может сработать тейк, стоп или одно из трех.
Таким образом из 80% вероятности достижения тейка остается всего 27%.
В случае установки стопа по цене открытия дня ситуация не лучше, из 10 дней — 2 по 0,5 литра убытка против 8 дней по 100 грамм прибыли.

Что ниже точки равновесия — система генерирует убытки.

Тут и сказочке конец, кто не слушал молодец.

Простыми словами: использование стопов не уменьшает ваши убытки — напротив увеличивает их.
В принципе это все, что нужно знать о стопах, алготрейдинге и вообще о бирже.

Что же делать? Спросите вы меня… Выход есть — изменить параметры системы.

Вернемся к графикам


ТС "Игра теней". Завязка.

Увеличение потенциального дохода до 0,2 процентов при снижении вероятности его достижения до 70%
дает нам 50% годовых, теже 2 дня по 0,5 против 7 дней по 0.2, ежедневная прибыль 4 сотых процента движения базового инструмента.
Система протестирована и неплохо работает на высоколиквидных маловолатильных инструментах. Как по настоящему прикрыть ваши задницы, в смысле депозиты расскажу в следующий раз, а пока держите скрипт расчета цен открытия позиции.

скопируйте его в файл, смените расширение на html, откройте в любом браузере.

Кнопка Laod data прочитает котировки с mdf, из-за ограничений безопасности javascript скачанный файл надо открыть, для этого вторая кнопка.
Читаются котировки инструментов входящих в индекс ММВБ на дату написания скрипта, где​ то 2 года назад, хотите что то добавить — добавьте коды инструментов в строку запроса.
Если получите ошибку 500 прочитайте данные еще раз, это внутренняя ошибка сервера.

На экране появится табличка в светофорном стиле, зеленый цвет — актив лучше рынка, даже если цена снижалась, красный — хуже, даже если цена росла.
Можете сменить период свечи на недельный — поставьте период = 8, заодно проверите систему AlexChi лучшие бумаги недели, или часовой период = 6,​
не забудьте поменять период запроса данных — расчетная переменная StartDate

Сортировка таблицы по доходности предпоследней свечи — хотите по последней найдите в тексте sort, поменяйте индекс массива на 0.
last — последняя цена, Buy — открытие + 0,5%, Sell — открытие — 0,5 %

Дальше интересней — не переключайтесь....

<!DOCTYPE html>
<meta charset="utf-8">
<html>
<body>

<a href="SomeLink" id="ButtonLoadData" download><input type='button' class='button-css' value='Load data...' /></a>
           
<input type="file" onChange="readFiles(this);" multiple />
<br>
<br>

<table id="table" border="1"></table>
<script> // загрузка файла
var DimTikers = [];
var DimColumns = [];
var iMoex;

/*
var Cost = {
	var Period;
	var Open;
	var Close;
	var Min;
	var Max;
	var Percent;
	};
	
var DimTiker={
	var Tiker;
	var Dividends[];
	var Cost = [];
};
*/
function readFiles(e)
{
    
		const files = e.files;
		readOneFile(0,files);

		function readOneFile(indexFiles,files){ 
			if (indexFiles>=files.length) { 
				return;
			}
			const file = files[indexFiles];
			
			const reader = new FileReader();
			reader.addEventListener('loadend', event => {
				let content = event.target.result;

				let rows = content.split(/\r\n|\r|\n/g);
				for (j=0; j<rows.length; ++j) {
					let row = rows[j].split(";");
					if (row[0]!="<TICKER>" && rows[j] ) {
						PosTiker=DimTikers.findIndex(item => item.Tiker == row[0]);
						if (PosTiker==-1) {PosTiker=DimTikers.length; DimTikers[PosTiker]={};DimTikers[PosTiker].Cost=[];}
						DimTikers[PosTiker].Tiker=row[0];
						if (DimColumns.findIndex(item => item==row[2])==-1) DimColumns[DimColumns.length]=row[2];
						DimTikers[PosTiker].Cost[row[2]]={Period:row[2], Open:row[4], Close:row[7], 
												  Low:row[6], High:row[5], 
												  Percent:(  row[4]==0 ? 0 : Math.trunc(10000* (row[7]-row[4])/row[4] )/100) };
						
						
					}
					
					
				}
				
				if (indexFiles+1==files.length){
						DimColumns.sort(function(a,b){ 
												//console.log("-"+a+" "+b);
												if (a>b) return -1; else if (a<b) return 1; else return 0;
												}
						);
						
						for (let i = 0; i < DimTikers.length; i++) {
							for (let j=0; j<DimColumns.length; j++){
									try {
										DimTikers[i].Cost[DimColumns[j]].Percent = (DimTikers[i].Cost[DimColumns[j+1]].Close==0) ? 0 : 
												Math.trunc(10000*(DimTikers[i].Cost[DimColumns[j]].Close-DimTikers[i].Cost[DimColumns[j+1]].Close)
												/DimTikers[i].Cost[DimColumns[j+1]].Close)/100;
									}
									catch{
										try {
											DimTikers[i].Cost[DimColumns[j]].Percent = (DimTikers[i].Cost[DimColumns[j]].Open==0) ? 0 : 
												Math.trunc(10000*(DimTikers[i].Cost[DimColumns[j]].Close-DimTikers[i].Cost[DimColumns[j]].Open)
												/DimTikers[i].Cost[DimColumns[j]].Open)/100;
										}
										catch{
										}
									}
							}
						}
						
						DimTikers.sort(function(a,b){ if (a.Cost[DimColumns[1]].Percent<b.Cost[DimColumns[1]].Percent) return 1; else if (a.Cost[DimColumns[1]].Percent>b.Cost[DimColumns[1]].Percent) return -1; else return 0;});
						//console.log(DimTikers);
						
						
						let table = document.querySelector('#table');

						let tr = document.createElement('tr');
						
						let td = document.createElement('td');
						tr.appendChild(td);
						
						let td3 = document.createElement('td'); //Last
						td3.innerHTML='Last';
						tr.appendChild(td3);
						
						let td1 = document.createElement('td'); //Buy
						td1.innerHTML='Buy';
						tr.appendChild(td1);
						
						let td2 = document.createElement('td'); //Sell
						td2.innerHTML='Sell';
						tr.appendChild(td2);
						
						
						
						
						for (let i=0; i<DimColumns.length; i++){
							
							let td = document.createElement('td');
							td.innerHTML=DimColumns[i].substring(6,8)+"."+DimColumns[i].substring(4,6);
							tr.appendChild(td);
						}
						table.appendChild(tr);
						iMoex=DimTikers.find(item => item.Tiker == "Индекс МосБиржи");
						for (let i = 0; i < DimTikers.length; i++) {
							
							let tr = document.createElement('tr'); //align="left"
							
							let td = document.createElement('td'); td.style.align="right";
							td.innerHTML=DimTikers[i].Tiker;
							tr.appendChild(td);
							
							let td3 = document.createElement('td'); td3.style.align="left"; //last
							td3.innerHTML=(DimTikers[i].Cost[DimColumns[0]].Close).toString().replace(".",",");
							tr.appendChild(td3);
							
							let td1 = document.createElement('td'); td1.style.align="left"; //buy
							//td1.innerHTML=(Math.trunc(100*(DimTikers[i].Cost[DimColumns[1]].High-(DimTikers[i].Cost[DimColumns[1]].High-DimTikers[i].Cost[DimColumns[2]].Low)/3))/100).toString().replace(".",",");
							
							td1.innerHTML=(Math.trunc(100*(DimTikers[i].Cost[DimColumns[1]].Open*1.005))/100).toString().replace(".",",");

							console.log(""+DimTikers[i].Tiker+"  "+DimTikers[i].Cost[DimColumns[1]].High+"   "+DimTikers[i].Cost[DimColumns[2]].Low+"   "+(DimTikers[i].Cost[DimColumns[1]].High-DimTikers[i].Cost[DimColumns[2]].Low)/3);
							tr.appendChild(td1);
							let td2 = document.createElement('td'); td2.style.align="left"; //Sell
							//td2.innerHTML=(Math.trunc(100*(DimTikers[i].Cost[DimColumns[1]].High-(DimTikers[i].Cost[DimColumns[1]].High-DimTikers[i].Cost[DimColumns[2]].Low)/1.5))/100).toString().replace(".",",");
							td2.innerHTML=(Math.trunc(100*(DimTikers[i].Cost[DimColumns[1]].Open*0.995))/100).toString().replace(".",",");
							tr.appendChild(td2);
							
							
							let summa=0;
							
							for (let j=0; j<DimColumns.length; j++){
								let td = document.createElement('td');
								let color="black";
									try{
										if  (iMoex.Tiker==DimTikers[i].Tiker) 
											color="black";
										else
											color = (iMoex.Cost[DimColumns[j]].Percent < DimTikers[i].Cost[DimColumns[j]].Percent) ? "green":"red";
									}
									catch {
										color="yellow";
									}
									
								try {
									td.innerHTML = '<span style="color: '+color+';">'+DimTikers[i].Cost[DimColumns[j]].Percent.toString().replace(".",",")+'</span>'; 
									}
								catch {
								}								
								
								tr.appendChild(td);
							}
							
							table.appendChild(tr);
						}

				}
			});

			reader.readAsText(file);
			readOneFile(indexFiles+1,files);
		}
}
</script>


<script>

var myUrl0='https://mfd.ru/export/handler.ashx/IMOEX_1week.txt?TickerGroup=14&Tickers=140335&Alias=false&Alias149952=IMOEX&Period=7&timeframeValue=1&timeframeDatePart=day&';


var myUrl='https://mfd.ru/export/handler.ashx/mfdexport.txt?TickerGroup=16&Tickers=145325%2C248695%2C246238%2C59186%2C237123%2C251365%2C231825%2C56252%2C202443%2C66525%2C66538%2C41369%2C183%2C258%2C330%2C336%2C121191%2C140335%2C489%2C629%2C632%2C832%2C82984%2C716%2C51353%2C826%2C913%2C948%2C330%2C336%2C121191%2C140335%2C489%2C629%2C632%2C832%2C82984%2C716%2C51353%2C826%2C913%2C948%2C1019%2C1279%2C103315%2C1373%2C54102%2C1383%2C246271%2C1389%2C1463%2C1464%2C913%2C948%2C1019%2C1279%2C103315%2C1373%2C54102%2C1383%2C246271%2C1389%2C1463%2C1476%2C1503%2C1542%2C1543%2C1613%2C1614%2C1658%2C37859%2C1712%2C107301&Alias=false&Period=7&timeframeValue=1&timeframeDatePart=day&';

var myUrl1='&SaveFormat=0&SaveMode=0&FileName=mfdexport.txt&FieldSeparator=%253b&DecimalSeparator=.&DateFormat=yyyyMMdd&TimeFormat=HHmmss&DateFormatCustom=&TimeFormatCustom=&AddHeader=true&RecordFormat=0&Fill=false';


var now = new Date();
var enddata = strRight(2,"0"+now.getDate().toString())+"."+strRight(2,"0"+(now.getMonth()+1).toString())+"."+now.getFullYear().toString();
var Month=now.getMonth()-1;var year=now.getFullYear();
if (Month<0) {Month=12+Month+1; year--;};
var startdata = strRight(2,"0"+now.getDate().toString())+"."+strRight(2,"0"+Month.toString())+"."+(year).toString();

myUrl2=myUrl+"StartDate="+startdata+"&EndDate="+enddata+myUrl1;

document.getElementById('ButtonLoadData').href = myUrl2;

function strRight(n,str){
   return str.substring(str.length-n,str.length);
   
   // параметр e - объект файла из элемента выбора
/**
 *
 * @param data данные из файла CSV
 * @param delimiter разделитель, используемый в файле
 * @param firstRow пропускать или оставлять первую строку - заголовок
 */
function convertCSV2Array(data, delimiter = ',', firstRow = false)
{
  return data
    .slice(firstRow ? data.indexOf('\n') + 1 : 0)
    .split('\n')
    .map(row => row.split(delimiter));
}
}
</script>
</body>
</html>


34 Комментария
  • Replikant_mih
    22 января 2023, 14:51
    При движении цены в одном направлении на пол-процента вероятность движения еще на одну десятую составляет 80%
    При этом вероятность возврата цены к открытию составляет 20%

    Итого получаем:

    плюсовое направление: 80% вероятности движения 0.1%.
    минусовое направление: 20% вероятности движения 0.5%

    мат. ожидание:

    плюсовое: 0.1 * 0.8 = 0.08%
    минусовое: 0.5 * 0.2 = 0.1%

    Где я ошибся?
      • Replikant_mih
        22 января 2023, 15:08
        Nekto Finkelmaer, а, это было начало рассуждения, я думал это основа стратегии и дальше не стал особо читать).
  • Активируйте, пожалуйста, windows
  • GAURANGA
    22 января 2023, 22:17
    Сломается.
  • Андрей &
    23 января 2023, 10:05
    Блин. Вы все такие умные математики, что жуть просто берёт и колени трястись начинают при виде тех цифер, что выше двух и имеют больше знаков нежели просто плюс и минус. Ну, а если серьёзно, то прежде чем писать код для робота, нужно разобраться досконально с самим исходным (кодом) рынка. Какие в жопу вероятности и проценты у вас берутся? Это возможно и работает на боле менее спокойном рынке… Хотя слово Возможно это скорее для поиграть. В любом месте всегда присутствует первое, изначальное место то откуда цена поворачивает, на откат либо для продолжения движения. Это то место где стоп всегда минимален. а зачастую ещё и прибылен. Такая точка входа всегда одна и неизменная в своём повторении. На любом рынке за исключением Форекс, хотя и там всё работает но с уточнением. Разберите для начала код рынка, а после делайте роботов. И код для робота в этом случае будет минимальным, а кол-во прибыльных сделок максимальным. К этому нужно стремиться, а не перебирать теории вероятностей.
      • Андрей &
        23 января 2023, 12:38
        Nekto Finkelmaer, Дело не в жопе, а не в продуманности стратегии. Возможно я не совсем понял сути, но перечитал несколько раз. Смысл конечно есть, но цена внезапного стопа весьма велика. Быть может, стоит несколько пересмотреть стратегию? Взять за исходную часовой ТФ. Робот автоматически ищет наивысшую точку обновившегося пика цены и при движении рынка в обратную сторону, бот, отсчитывает от образовавшегося максимума те самые 0,5% и открывает сделку в направлении движения? В таком варианте есть более высокая вероятность взятия более значимого профита нежели сотые доли. Единственное, чему робота нужно научить это грамотному закрытию сделок, что бы вытащить из позиции максимально возможную прибыль. Мой робот так и работает. Подхватывает мною открытую позицию и тянет всё возможное. И да, что бы повысить точность определения когда роботу считать начало движения, я бы предложил брать последнюю свечу чьё тело закрылось выше хвостов предыдущих свечей. В таком случае, можно избежать тот процент холостых срабатываний, когда рынок находится в боковике. Поглядите сами на истории. Эта стратегия на Н1, будет работать на любом рынке. Единственно, что опасно в такой стратегии это торговля фьючерсами на всю котлету. А вот акциями самое оно. Лично от себя, могу предложить менее рисковую стратегию где тем же роботом, можно брать от двух и более сделок за торговую сессию с минимальным стопом и в случае разворота рынка против, забирать всё те же цифры, описанные в вашей стратегии.
          • Андрей &
            23 января 2023, 17:28
            Nekto Finkelmaer, продолжение последует если это кому то нужно будет, а так расписывать пару сотен букв в воздух — смысл? Ради интереса, погонял на истории вашу стратегию принципа 0,5% движения цены. Взял фьючерс рубля/доллар, юань/рубль и пару российских акций. За основу, часовой ТФ. Отсчёт в обратную сторону, брал от максимума текущего часа. Результат… пугающий. В хорошем смысле. Если брать на примере (сишки), то по стопу в те же 0,5% сносит раз в несколько месяцев. В остальное время, идёт набор прибыли. Можно организовать усреднение и снизить коэфф. убытка, но такое не по мне. Самое сложное это фиксация прибыли. Здесь нужно думать алгоритм загрузки/разгрузки со смещением стопа. Цена довольно часто, даёт весьма мощные движения, а иногда всего 100-200 пунктов. В общем, буду думать. Сейчас же на обкатку, поставил робота в боевое (дежурство) работать по этому принципу т.е. только на открытие позиции. (тащить) сделку будет другой робот, специально под это заточенный, но думаю, что в таком случае, алгоритм должен быть совершенно иной. Поглядим, что из всего этого выйдет в реале через пару месяцев. Но вообще, идея неплохая. Весьма. В дальнейшем, можно попробовать, загнать её на Форекс. Там где отсутствует реальное отображение графика объёма, подобная стратегия будет очень хороша. Ещё хороший вариант, торговать подобную стратегию на открытии рынка от максимума предыдущего дня. Зачастую, это даёт самые жирные куски. В общем, как вариант для тех кто не особо заморачивается кратковременной просадкой в несколько сот пунктов, а так же иногда потери 0,5% от суммы входа, стратегия вполне имеет право на существование.
  • svgr
    23 января 2023, 15:23
    Система протестирована и неплохо работает на высоколиквидных маловолатильных инструментах.
    Можно ли увидеть результаты тестов?
    И как вот из этого:
    При движении цены в одном направлении на пол-процента вероятность движения еще на одну десятую составляет 80%
    При этом вероятность возврата цены к открытию составляет 20%
    можно сделать вывод: 
    Направленное движение всегда продолжается.
    Надо бы определить сначала и в цифрах изобразить, что значит направленное. Тогда и проверить что-то возможно станет.
  • svgr
    23 января 2023, 16:24
    И это, не видите ли косяка в построениях?
    Для анализа также потребуется потенциальный размер дохода
    — в случае зеленой свечи (Закрытие-Открытие)/Открытие
    — в случае красной свечи (Открытие-Закрытие)/Открытие
    На открытии Вы не знаете цвет начатой свечи, а используете его в вычислениях. )
      • svgr
        23 января 2023, 21:27
        Nekto Finkelmaer, по-прежнему имеются сомнения в верности рассуждений. 
        1) Если минимум текущей свечи отклонился от её открытия более чем на 0,5%, то ничто не мешает в этой же свече переписать максимум так же более чем на 0,5% от открытия. Как-то это в статистике учитывается?
        2) Не ясно в какой момент входить и в какую сторону. Преодоление минимального отклонения в 0,5% никак статистически не влияет на последующее поведение цены в оставшееся время свечи. Оно по-прежнему равновероятно в обе стороны. Легко проверяется тестами.
  • svgr
    23 января 2023, 23:02
    Теперь более понятно. Составлял аналогичную статистику не для свечей, а для зигзага лет пять назад.
    Какие выводы по представленному подходу? 
    Вы должны выбрать период свечей, в котором статистика наиболее проявлена в нужном ключе. Для одного инструмента он более-менее стабилен.
    Это всё слегка взлетит только для некоторых инструментов.
    В общем случае устойчивого заработка нет. Мелкие выигрыши по 0,1-0,2% съест комиссия более чем наполовину. А добьют накопленный небольшой плюс те 20% случаев больших сливов, когда будут случаться походы к противоположным полюсам свечи.
      • svgr
        24 января 2023, 08:51
        Nekto Finkelmaer, когда повертите больше отрезков времени, инструментов, увидите, что дела обстоят так, как я описал. Например, ваши 0,54% и 5% в годах 2018 или 2015 перестанут быть лучшими. Может и убыток возникнуть.
        Следующим шагом надо увидеть, что есть инструменты и ТФ, при которых входить надо вообще в другую сторону.
        А общее замечание — в вашем подходе нужно использовать логарифмы цен. Сейчас у Вас % вверх ничем не ограничен, а вниз только 100%. Статистика перекошена.
          • svgr
            24 января 2023, 11:12
            Nekto Finkelmaer, последний пост в рамках помощи. Думаю, бесполезно.
            Вероятности, на которые Вы уповаете, надо уметь считать. Или получить иным достоверным способом.
            Сгенерируйте СБ. Это тоже нетривиальная задача — сгенерировать свечи, полученные по СБ. Постройте ваши линии на них. Характеристика линии входа при СБ — нулевое матожидание результата для каждой точки входа при нулевой комиссии.
            Затем откладываете двойную комиссию от неё вверх и вниз для данной цены. Получите коридор, в котором выходы будут убыточными из-за комиссии. 
            После чего можете строить линию выходов реального инструмента. Для входа в продолжение она должна быть выше коридора входов, для входа на возврат — ниже коридора. Расстояния от выходов до коридора и есть средний доход на одну сделку (вх+вых).

Активные форумы
Что сейчас обсуждают

Старый дизайн
Старый
дизайн