Избранное трейдера Mantis
Для анализа будем использовать данные ETF c базовой валютой USD: FXCN, FXRL, FXIT, FXUS и FXRU. Временной ряд рассмотрим за три года с 2018 по 2020 года. Само исследование проведем в Google Colaboratory.
Как обычно в начале импортируем все необходимые библиотеки для дальнейшей работы.
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from google.colab import files
import warnings
warnings.filterwarnings("ignore")Сначала необходимо получить данные. Есть несколько способов. Мы воспользовались — взяли их с Finam в формате csv. Дальше написал функцию для обработки полученных данных и при помощи concat свел их в один датафрейм.def changeDF(df): df['date'] = pd.to_datetime(df['<DATE>'].astype(str), dayfirst=True) name =[x for x in globals() if globals()[x] is df][0] df = df.drop(['<DATE>','<TIME>', '<OPEN>', '<HIGH>', '<LOW>'], axis=1) df = df.set_index(['date']) df.columns = [name+'_cl', name + '_vol'] return df fxgd_change = changeDF(fxgd) fxrl_change = changeDF(fxrl) fxit_change = changeDF(fxit) fxus_change = changeDF(fxus) fxru_change = changeDF(fxru) fxcn_change = changeDF(fxcn) etf = pd.concat([fxgd_change, fxrl_change, fxit_change, fxus_change, fxru_change, fxcn_change], axis=1) etf.head()В результате получили:
Завтра (16 сентября) начнётся сбор заявок на выпуск 5-летних облигаций Mail.ru на 10 млрд. руб. Насколько привлекательно это размещение для розничных инвесторов, которые уже ни во что не верят и ничего не ждут от Mail.ru? Для справки: акции -20% c начала 2021 года.
Мы считаем, что привлекательно:
Во-первых, Mail.ru, хоть и остаётся вечным номером 2 на российском IT-рынке (после Яндекса), все же имеет пул сильных продуктов, которыми регулярно пользуются более 70 млн человек. Сюда относятся соцсети (ВКонтакте, Одноклассники), платформы онлайн-образования (GeekBrains, SkillBox), онлайн-игр (MY.GAMES), частных объявлений (Юла) и онлайн-рекламы (собственно, сам Mail).
Во-вторых, каждое из направлений генерирует денежный поток для компании, что выливается в хорошее финансовое положение (рентабельность EBITDA стабильно выше 20%) с низкой долговой нагрузкой (ND/EBITDA — 1.3х), которая значительно не пострадает от привлечения нового долга.
import sqlite3 as sql
from scipy.stats import logistic
import math
import numpy as np
import numpy.random as rnd
import matplotlib.pyplot as plt
from sklearn.neural_network import MLPRegressor
sdata =[]
sql1= "select ticker, date, open, high, low, close, vol \
from Hist_1m where ticker_id=1 order by Date;"
con=sql.connect('C:/Users/ubase/Documents/StockDB/StockDB21.sqlite')
cur=con.cursor()
cur.execute(sql1)
sdata=cur.fetchall()
con.commit()
con.close()
Ldata = len(sdata)
N = 8000 # Количество сделок
ld = 5 #Продолжительность сделки
NNinterval = 20 # Количество входов NN
# Генерация случайных чисел
rng = rnd.default_rng()
rm=rng.integers(0, Ldata, N )
class Candle:
tr = 0
dt = 1
o = 2
h = 3
l = 4
c = 5
v = 6
cl = Candle
DataC =[sdata[i][cl.c] for i in range(0,Ldata)]
# sigmoid линейность до 0.5
def sigmoidnorm(x, alfa = 0.9, xmin = -1.3, xmax = 1.3):
return (xmax - xmin)*((1 / (1 + math.exp(-x*2.0*alfa))) - 1.0) + xmax
x = [0.002 * i - 3 for i in range(0,3000)]
y = [sigmoidnorm(x[i]) for i in range(len(x))]
plt.plot(x,y)
plt.grid()
plt.show()
# формируем сделки.
def DealsGenL(rm,ld):
#Lm = len(rm)
ix = []
x = []
pr = []
for i in range(0,N):
if rm[i] + ld < Ldata and rm[i] - NNinterval - 1 > 0:
delta = (sdata[rm[i]+ld][cl.c] - sdata[rm[i]][cl.c])/sdata[rm[i]+ld][cl.c]*100
x0 = [sigmoidnorm((sdata[rm[i] - j][cl.c] - sdata[rm[i]][cl.c])/sdata[rm[i]][cl.c]*100) \
for j in range(0, NNinterval)]
ix.append(rm[i])
x.append(x0)
pr.append(delta)
return ix, x, pr
Ix, X, Pr = DealsGenL(rm,ld)
Ib = 0
Ie = 100
plt.plot(X)
plt.legend()
plt.grid()
plt.show()
plt.plot(Pr, label = 'Prof')
plt.legend()
plt.grid()
plt.show()
regr = MLPRegressor(hidden_layer_sizes = [30,20,15,10,5], \
max_iter=500, activation = 'tanh')
regr.fit(X, Pr)
Out = regr.predict(X)
plt.plot(Pr, Out, '.')
plt.grid()
plt.show()И вот результат прогнозирования:После многих сотен часов, проведённых за финансовым анализом российских предприятий, приходит день, когда в руки попадает баланс динамично и уверенно развивающейся молодой компании. Такой баланс приятно читать и анализировать. Жаль, что не многие предприятия, в любой сфере, могут похвастать своим финансовым положением, как это делает ООО «Бифорком Текнолоджис» .


--[[
индикатор торговой системы QUIK:
канал на последнем зигзаге
индикатор строит канал по зигзагу, показывает слом тренда при выходе цены за границы канала
параметры:
Procent - величина зигзага в %
k - коэффизиент ширины канала
Ext - =0-канал стоится по средним =1-канал стоится по экстремуму
Как им пользоваться:
в папке QUIK\LuaIndicators создаем текстовый файл с содержимым кода индикатора
добавляем индикатор на график
задаем параметр чувствиельности инлдикатора — Процент
индикатор показывает уровни, в которых находится тренд
если тренд еще не сформировался, то границы канала могут расширяться по мере движения цены
если в канале уже есть локальные вершины, то при следующем походе индикатора к границе канал возмен разворот тренда или коррекции в рамках данного канала
--]]
Settings=
{
Name = "Zigzag_channel_fast", -- название индикатора
Procent=5.0, -- величина зигзага в %
k=2, -- коэффизиент ширины канала
Ext=1, -- =0-канал стоится по средним =1-канал стоится по экстремуму
shif=0,
line=
{
{
Name = "zigzagline",
Type =TYPE_LINE,
Width = 1,
Color = RGB(120,90, 140)
},
{
Name = "cur1",
Type =TYPE_LINE,
Width = 1,
Color = RGB(0,0, 0)
},
{
Name = "cur2",
Type =TYPE_LINE,
Width = 2,
Color = RGB(0,200, 200)
},
{
Name = "cur3",
Type =TYPE_LINE,
Width = 2,
Color = RGB(200,200, 0)
},
{
Name = "cur4",
Type =TYPE_LINE,
Width = 1,
Color = RGB(0,0, 0)
},
{
Name = "cur5",
Type =TYPE_LINE,
Width = 2,
Color = RGB(0,0, 255)
},
{
Name = "cur6",
Type =TYPE_LINE,
Width = 2,
Color = RGB(255,0, 0)
},
{
Name = "cur7",
Type =TYPE_LINE,
Width = 2,
Color = RGB(255,0, 0)
},
{
Name = "cur8",
Type =TYPE_LINE,
Width = 2,
Color = RGB(255,0, 0)
},
{
Name = "cur9",
Type =TYPE_LINE,
Width = 2,
Color = RGB(255,0, 0)
},
{
Name = "cur10",
Type =TYPE_LINE,
Width = 2,
Color = RGB(255,0, 0)
},
{
Name = "cur11",
Type =TYPE_LINE,
Width = 2,
Color = RGB(255,0, 0)
}
}
}
function Init()
y1 = nil
y2 = nil
y3 = nil
x1 = 1
x2 = 1
x3 = 1
oldindex = 1
a_01 = 0
b_01 = 0
a_02 = 0
b_02 = 0
vminus_01 = 0
vplus_01 = 0
vminus_02 = 0
vplus_02 = 0
vFrom_01 = 1
vTo_01 = 1
vFrom_02 = 1
vTo_02 = 1
vminus = 0
vplus = 0
vminus_n = 0
vplus_n = 0
ret = 0
last_ind = 1
v1=nil
v2=nil
v3=nil
v4=nil
v5=nil
v6=nil
v7=nil
v8=nil
v9=nil
v10=nil
return 10
end
function recalcline(num, index, rec)
if index == Size()-sh and rec == 0 then
for i = 1, index do
if m == 1 then
SetValue(i, 3, nil)
SetValue(i, 4, nil)
end
if m == 2 then
SetValue(i, 6, nil)
SetValue(i, 7, nil)
end
end
end
if index == Size()-sh or rec == 1 then
if num == 1 then
vFrom = 0 --[[ --]]
vTo = 0
if x3 < x2 then
vFrom = x3
vTo = x2
else
vFrom = x2
vTo = x3
end
end
if num == 2 then
vFrom = 0
vTo = 0
if x1 < x2 then
vFrom = x1
vTo = x2
else
vFrom = x2
vTo = x1
end
end
if vFrom < 1 then
vFrom = 1
end
a1 = 0
a2 = 0
a3 = 0
a4 = 0
n = 0
a = 0
b = 0
for i = vFrom, vTo do
n=n+1
a1 = a1+i*C(i)
a2 = a2+i
a3 = a3+C(i)
a4 = a4+i*i
end
if((n*a4 - a2*a2) ~= 0) then
-- if oldindex ~= Size() then
a = (n*a1 - a2*a3)/(n*a4 - a2*a2)
b = (a3 - a*a2)/n
vminus = 0
vplus = 0
vminus_n = 0
vplus_n = 0
for i = vFrom, index do
y = a*i + b
if i>0 then
if C(i) < y and i <= vTo then
if ex == 0 then
vminus = vminus + y - C(i)
vminus_n = vminus_n + 1
else
if i == vFrom then
vminus = 0
end
if y-C(i) > vminus then
vminus = y-C(i)
end
end
end
end
if i>0 then
if C(i) > y and i <= vTo then
if ex == 0 then
vplus = vplus + C(i) - y
vplus_n = vplus_n + 1
else
if i == vFrom then
vplus = 0
end
if C(i)-y > vplus then
vplus = C(i)-y
end
end
end
end
m = 0
if C(vTo) > C(vFrom) and y < C(vTo)+0.1*(C(vTo)-C(vFrom)) and y > C(vFrom)-0.1*(C(vTo)-C(vFrom)) then
m = 1
end
if C(vTo) < C(vFrom) and y < C(vFrom)+0.1*(C(vFrom)-C(vTo)) and y > C(vTo)-0.1*(C(vFrom)-C(vTo)) then
m = 1
end
if m == 1 then
--SetValue(i, 2, y)
end
end
--end
if ex == 0 then
if vminus_n ~= 0 then
vminus = kk*vminus/vminus_n
end
if vplus_n ~= 0 then
vplus = kk*vplus/vplus_n
end
end
end
if num == 1 then
a_01 = a
b_01 = b
vminus_01 = vminus
vplus_01 = vplus
vFrom_01 = vFrom
vTo_01 = vTo
end
if num == 2 then
a_02 = a
b_02 = b
vminus_02 = vminus
vplus_02 = vplus
vFrom_02 = vFrom
vTo_02 = vTo
end
return 1
end
return 0
end
function levels(x, y, num, index)
if y ~= nil and x ~= 1 then
for i = 1, index do
if i > x then
SetValue(i, num, y)
else
SetValue(i, num, nil)
end
end
end
end
function OnCalculate(index)
de = Settings.Procent
kk = Settings.k
ex = Settings.Ext
sh = Settings.shif
v1=nil
v2=nil
v3=nil
v4=nil
v5=nil
v6=nil
v7=nil
v8=nil
v9=nil
v10=nil
if index > Size()-sh then
--return nil, nil, nil, nil, nil, nil, nil
return v1, v2, v3, v4, v5, v6, v7, v8, v9, v10
end
vl = C(index)
if vl~=nil then
if index == 1 then
y1 = vl
y2 = vl
else
if C(index) > y1*(1+de/100) and y1 < y2 then
x3 = x2
x2 = x1
y3 = y2
y2 = y1
x1 = index
y1 = C(index)
ret = recalcline(1, index, 0)
ret = recalcline(2, index, 0)
levels(x1, y1, 8, index)
levels(x2, y2, 9, index)
levels(x3, y3, 10, index)
end
if C(index) > y1 and C(index) > y2 then
x1 = index
y1 = C(index)
end
if C(index) < y1*(1-de/100) and y1 > y2 then
x3 = x2
x2 = x1
y3 = y2
y2 = y1
x1 = index
y1 = C(index)
ret = recalcline(1, index, 0)
ret = recalcline(2, index, 0)
levels(x1, y1, 8, index)
levels(x2, y2, 9, index)
levels(x3, y3, 10, index)
end
if C(index) < y1 and C(index) < y2 then
x1 = index
y1 = C(index)
end
end
end
--[[
if x1 ~= index then
curfrom = x1
curto = index
else
curfrom = x2
curto = x1
end
if curto ~= curfrom and curfrom ~= nil and curto ~= nil then
if C(curto) ~= nil and C(curfrom) ~= nil then
k = (C(curto)- C(curfrom))/(curto- curfrom)
for i = curfrom, index do
curv = i*k + C(curto) - curto*k
SetValue(i, 1, curv)
end
end
end
--]]
if index == Size()-sh and ret == 0 then
lpr = C(Size()-sh)
ret = recalcline(1, index, 1)
ret = recalcline(2, index, 1)
if y1 ~= nil then
if y1 > lpr*0.9 and y1 < lpr*1.1 then
levels(x1, y1, 8, index)
end
end
if y2 ~= nil then
if y2 > lpr*0.9 and y2 < lpr*1.1 then
levels(x2, y2, 9, index)
end
end
if y3 ~= nil then
if y3 > lpr*0.9 and y3 < lpr*1.1 then
levels(x3, y3, 10, index)
end
end
end
if index == Size()-sh then --- and index ~= last_ind
if vTo_01 - vFrom_01 > 500 then
vFrom_01 = vTo_01-500
end
for i = 1, index do
SetValue(i, 3, nil)
SetValue(i, 4, nil)
SetValue(i, 6, nil)
SetValue(i, 7, nil)
-- SetValue(i, 8, nil)
-- SetValue(i, 9, nil)
-- SetValue(i, 10, nil)
end
for i = vFrom_01, index do
y = a_01*i + b_01 + vplus_01
m = 0
if C(vTo_01) > C(vFrom_01) and y < C(vTo_01)+0.3*(C(vTo_01)-C(vFrom_01)) and y > C(vFrom_01)-0.3*(C(vTo_01)-C(vFrom_01)) then
m = 1
end
if C(vTo_01) < C(vFrom_01) and y < C(vFrom_01)+0.3*(C(vFrom_01)-C(vTo_01)) and y > C(vTo_01)-0.3*(C(vFrom_01)-C(vTo_01)) then
m = 1
end
if m == 1 then
SetValue(i, 3, y)
if i == index then
v3 = y
end
end
y = a_01*i + b_01 - vminus_01
m = 0
if C(vTo_01) > C(vFrom_01) and y < C(vTo_01)+0.3*(C(vTo_01)-C(vFrom_01)) and y > C(vFrom_01)-0.3*(C(vTo_01)-C(vFrom_01)) then
m = 1
end
if C(vTo_01) < C(vFrom_01) and y < C(vFrom_01)+0.3*(C(vFrom_01)-C(vTo_01)) and y > C(vTo_01)-0.3*(C(vFrom_01)-C(vTo_01)) then
m = 1
end
if m == 1 then
SetValue(i, 4, y)
if i == index then
v4 = y
end
end
end
if vTo_02 - vFrom_02 > 500 then
vFrom_02 = vTo_02-500
end
for i = vFrom_02, index do
y = a_02*i + b_02 + vplus_02
m = 0
if C(vTo_02) > C(vFrom_02) and y < C(vTo_02)+0.1*(C(vTo_02)-C(vFrom_02)) and y > C(vFrom_02)-0.1*(C(vTo_02)-C(vFrom_02)) then
m = 1
end
if C(vTo_02) < C(vFrom_02) and y < C(vFrom_02)+0.1*(C(vFrom_02)-C(vTo_02)) and y > C(vTo_02)-0.1*(C(vFrom_02)-C(vTo_02)) then
m = 1
end
if m == 1 then
SetValue(i, 6, y)
if i == index then
v6 = y
end
end
y = a_02*i + b_02 - vminus_02
m = 0
if C(vTo_02) > C(vFrom_02) and y < C(vTo_02)+0.1*(C(vTo_02)-C(vFrom_02)) and y > C(vFrom_02)-0.1*(C(vTo_02)-C(vFrom_02)) then
m = 1
end
if C(vTo_02) < C(vFrom_02) and y < C(vFrom_02)+0.1*(C(vFrom_02)-C(vTo_02)) and y > C(vTo_02)-0.1*(C(vFrom_02)-C(vTo_02)) then
m = 1
end
if m == 1 then
SetValue(i, 7, y)
if i == index then
v7 = y
end
end
end
last_ind = index
end
return v1, v2, v3, v4, v5, v6, v7, v8, v9, v10
end
Доходность портфелей PRObonds за последние 365 дней – 12,9% у облигационного портфеля #1, 9,7% у смешанного портфеля #2. За этот же период базовый индекс Cbonds-CBI RU High Yield за это же время вырос на 12,5%, так что портфель ВДО в нашем исполнении выглядит несколько лучше, чем сегмент в среднем.

Settings={
Name="Buy_osc_v01",
period=50,
delta=0,
lim=100.0,
line=
{
{
Name = "cur1",
Type =TYPE_LINE,
Width = 1,
Color = RGB(0, 0, 255)
},
{
Name = "cur2",
Type =TYPE_LINE,
Width = 1,
Color = RGB(0, 0, 0)
},
{
Name = "cur3",
Type =TYPE_LINE,
Width = 1,
Color = RGB(0,0, 0)
},
{
Name = "cur4",
Type =TYPE_LINE,
Width = 1,
Color = RGB(0,0, 0)
}
}
}
--[[
описание свойств:
period - период, за каротрый делается расчет
delta - смещение назад
назначение:
горизонтальная ширина канала
использовался:
метод наименьших квадратов (аппроксимация линией)
--]]
function Init()
return 2
end
function OnCalculate(index)
sz = Size()
n = Settings.period
d = Settings.delta
lim = Settings.lim
y = nil
if index-n-d > 0 then
a1 = 0
a2 = 0
a3 = 0
a4 = 0
for i=index-n+1-d, index-d do
a1 = a1+i*C(i)
a2 = a2+i
a3 = a3+C(i)
a4 = a4+i*i
end
if((n*a4 - a2*a2) ~= 0) then
a = (n*a1 - a2*a3)/(n*a4 - a2*a2)
b = (a3 - a*a2)/n
c1 = 0
c2 = 0
n1 = 0
n2 = 0
for j=index-n+1-d, index-d do
y = a*j + b
if C(j) < y then
c1 = c1 + (y -C(j))
n1 = n1 + 1
end
if C(j) > y then
c2 = c2 + (C(j) - y)
n2 = n2 + 1
end
end
if n1 ~= 0 then
c1 = c1/n1
end
if n2 ~= 0 then
c2 = c2/n2
end
if a==0 then
y = 0
else
y = (c1+c2)/a
if y > lim then
y = lim
else
if y < -lim then
y = -lim
end
end
end
end
end
return y,0
endЗахотелось реализовать несколько идей для быстрого расчета по позициям акций и для этого мне нужно было чтобы скрипт на python постоянно получал обновленное значение цены. Например раз в три секунды. Искал решение и нашел похожий пример с парсингом любой информации в интернете на python с применением блиотек requests и beautiful soup, (bs4).
