<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title><![CDATA[QUIK -> DDE &mdash; Советы]]></title>
		<link>https://quik2dde.ru/viewtopic.php?id=297</link>
		<atom:link href="https://quik2dde.ru/extern.php?action=feed&amp;tid=297&amp;type=rss" rel="self" type="application/rss+xml" />
		<description><![CDATA[Недавние сообщения в теме «Советы».]]></description>
		<lastBuildDate>Wed, 11 Sep 2019 22:46:04 +0000</lastBuildDate>
		<generator>PunBB</generator>
		<item>
			<title><![CDATA[Re: Советы]]></title>
			<link>https://quik2dde.ru/viewtopic.php?pid=2439#p2439</link>
			<description><![CDATA[<div class="quotebox"><cite>Andrei1101 пишет:</cite><blockquote><p>Вопрос: зачем присваивать пустую таблицу при индексе свечи 1<br /></p><div class="codebox"><pre><code>  if index == 1 then 
      cache = {} 
    end </code></pre></div><p>когда в теле основной функции уже есть<br /></p><div class="codebox"><pre><code>local cache={}</code></pre></div><p>?</p></blockquote></div><p>При вызове cached_EMA() создается замыкание.<br />Допустим вы хотите в индикаторе 3 линии ема с разными периодами. Для этого вы создаете 3 замыкания:<br /></p><div class="codebox"><pre><code>myEma1 = cached_EMA()
myEma2 = cached_EMA()
myEma3 = cached_EMA()</code></pre></div><p>Каждая из функций myEma1-3 имеет свой собственный cache, объявленный в cached_EMA() и видимый только для своего замыкания.<br />А блок кода:<br /></p><div class="codebox"><pre><code>  if index == 1 then 
      cache = {} 
  end </code></pre></div><p>нужен для обнуления массива cache при изменении настроек индикатора или таймфрейма графика.</p>]]></description>
			<author><![CDATA[null@example.com (kalikazandr)]]></author>
			<pubDate>Wed, 11 Sep 2019 22:46:04 +0000</pubDate>
			<guid>https://quik2dde.ru/viewtopic.php?pid=2439#p2439</guid>
		</item>
		<item>
			<title><![CDATA[Re: Советы]]></title>
			<link>https://quik2dde.ru/viewtopic.php?pid=2438#p2438</link>
			<description><![CDATA[<p>В примерах создания индикатора на&nbsp; Lua приведена функция скользящей средней с использованием замыканий для сохранения предыдущих значений:<br /></p><div class="codebox"><pre><code>function cached_EMA() 
  local cache={} 
  return function(ind, _p, v_t, kk) 
    local n = 0 
    local p = 0 
    local period = _p 
    local v_type = v_t 
    local index = ind 
    local k = kk or 2/(period+1) 
    if index == 1 then 
      cache = {} 
    end 
    if index &lt; period then 
      cache[index] = average(1,index, v_type) 
      return nil 
    end 
    p = cache[index-1] or dValue(index, v_type) 
    n = k*dValue(index, v_type)+(1-k)*p 
    cache[index] = n 
    return n 
  end 
end </code></pre></div><p>Вопрос: зачем присваивать пустую таблицу при индексе свечи 1<br /></p><div class="codebox"><pre><code>  if index == 1 then 
      cache = {} 
    end </code></pre></div><p>когда в теле основной функции уже есть<br /></p><div class="codebox"><pre><code>local cache={}</code></pre></div><p>?</p>]]></description>
			<author><![CDATA[null@example.com (Andrei1101)]]></author>
			<pubDate>Wed, 11 Sep 2019 16:06:23 +0000</pubDate>
			<guid>https://quik2dde.ru/viewtopic.php?pid=2438#p2438</guid>
		</item>
		<item>
			<title><![CDATA[Re: Советы]]></title>
			<link>https://quik2dde.ru/viewtopic.php?pid=2430#p2430</link>
			<description><![CDATA[<div class="quotebox"><cite>reader пишет:</cite><blockquote><p>Можно написать ещё короче.</p></blockquote></div><p>Можно, но в скрипте больше нет места для ваших max и min и нигде больше нет для них места, зачем тогда их писать? Мало того, вы делаете дополнительную проверку.<br />Краткость в написании скрипта - не всегда сестра таланта.<br /></p><div class="quotebox"><cite>reader пишет:</cite><blockquote><p>п.2 - сомнительный. Представьте, что у вас 3 десятка функций, которые вызываются в сотне мест. И вы решили, например, добавить аргументы в функцию или поменять их местами...</p></blockquote></div><p>представил, это глупость, менять параметры в функции, которая используется в 30 местах и возможно в еще большем кол-ве скриптов, ради одного использования, проще сделать новую функцию с префиксом Ex и написать там параметры так, как вам удобно.<br /></p><div class="quotebox"><cite>reader пишет:</cite><blockquote><p>п.4 - проверки типов лучше делегировать программе<br />function String(x)<br />&nbsp; &nbsp; &nbsp;if type(x) ~= &quot;string&quot; then return tostring(x) end<br />&nbsp; &nbsp; &nbsp;return x<br />end</p></blockquote></div><p>не лучше, я предлагаю избавиться от лишних проверок, вы их навязываете.<br /></p><div class="quotebox"><cite>reader пишет:</cite><blockquote><p>п.6 - доступ к глобальным переменным дольше потому что они ищутся в таблице по имени. Но модули - тоже таблицы.<br />Поэтому os_time() - вызов локальной функции быстрее чем os.time(), что то же самое os[&quot;time&quot;]() - поиск функции в таблице по имени и её вызов.</p></blockquote></div><p>Вы не совсем правы, поиск в локальной таблице будет быстрее, чем в глобальной, потому что локальная таблица находится ближе к вершине стека или вообще в регистре процессора.<br />А функция поиска по таблице будет искать с одинаковой скоростью. Про модули почитайте тоже повнимательнее букварь от автора.<br /></p><div class="quotebox"><cite>reader пишет:</cite><blockquote><p>По обработке ошибок есть удобный шаблон - всегда возвращать из функции пару значений - результат функции и сообщение об ошибке.</p></blockquote></div><p>Т.е. вы откуда то сковырнули фрагмент кода, который даже не удосужились проверить. Где функция do_something(val)?<br />Проверку if x &gt;= 0 лучше делать до вызова Sqrt(x), тогда в этой функции отпадет необходимость и не нужно обрабатывать сообщение об ошибки, т.к. ее не будет.<br />print( Sqrt(-1)+Sqrt(9)) выдает ошибку: &quot;attempt to perform arithmetic on a nil value&quot; - это не похоже на описание ошибки, переданное вторым параметром в функции Sqrt(x)<br />Плохой примерчик.<br />Вообще манечка &quot;примитивов&quot; это не есть гуд (а в ваших примерах масло-маслянное). Если всю логику скрипта разложить на примитивы, то без основательных комментариев(и даже с ними) не будет возможности понять основную идею, заложенную в скрипте, уже через неделю.</p><p>з.ы.<br />А на счет погугли и подбери, 99% гугленных библиотек не приживаются в рамках терминала квик без танцев с бубнов, потому что там колеса квадратные, а когда приживаются, то выясняется, что из библиотеки нужны всего пару функций, без которых можно обойтись.</p>]]></description>
			<author><![CDATA[null@example.com (kalikazandr)]]></author>
			<pubDate>Mon, 19 Aug 2019 22:45:12 +0000</pubDate>
			<guid>https://quik2dde.ru/viewtopic.php?pid=2430#p2430</guid>
		</item>
		<item>
			<title><![CDATA[Re: Советы]]></title>
			<link>https://quik2dde.ru/viewtopic.php?pid=2429#p2429</link>
			<description><![CDATA[<p>Можно написать ещё короче.<br /></p><div class="codebox"><pre><code>local function max(a,b) return a&gt;=b and a or b end
local function min(a,b) return a&gt;=b and b or a end
local sign_func = {
  [-1]= function(o,h,c,l) return min(o,c) end,
  [0] = function(o,h,c,l) return (o+h+c+l)/4 end,
  [1] = function(o,h,c,l) return max(o,c) end
}

-- signal по умолчанию число [-1; 1], его проверять не будем
local function fn(ds, signal)

  local index = ds:Size()
  if index == 0 then return 0 end

  local O, H, L, C = ds:O(index),  ds:O(index), ds:O(index), ds:O(index)
  if O == 0 or H == 0 or L == 0 or C == 0 then return 0 end

  return sig_func[signal](O,H,C,L)
end</code></pre></div><p>п.2 - сомнительный. Представьте, что у вас 3 десятка функций, которые вызываются в сотне мест. И вы решили, например, добавить аргументы в функцию или поменять их местами...</p><p>п.4 - проверки типов лучше делегировать программе<br />function String(x)<br />&nbsp; &nbsp; &nbsp;if type(x) ~= &quot;string&quot; then return tostring(x) end<br />&nbsp; &nbsp; &nbsp;return x<br />end</p><p>п.6 - доступ к глобальным переменным дольше потому что они ищутся в таблице по имени. Но модули - тоже таблицы.<br />Поэтому os_time() - вызов локальной функции быстрее чем os.time(), что то же самое os[&quot;time&quot;]() - поиск функции в таблице по имени и её вызов.</p><p>По обработке ошибок есть удобный шаблон - всегда возвращать из функции пару значений - результат функции и сообщение об ошибке.<br /></p><div class="codebox"><pre><code>function Sqrt(x)
    if x&gt;=0 then return math.sqrt(x), nil end
    return nil, &quot;Error: x&lt;0&quot;
end

val,err = Sqrt(100)
if err then
   error( err)
end
do_something(val) 

-- можно даже игнорировать проверку ошибок
print( Sqrt(4)+Sqrt(9))
--&gt;&gt; 5</code></pre></div><p>p.s. А лучше не изобретать велосипеды, погуглить awesome-lua (первые 3 ссылки на github) и подобрать себе библиотеку по вкусу. Рекомендую начать с Underscore.lua и Penlight.</p>]]></description>
			<author><![CDATA[null@example.com (reader)]]></author>
			<pubDate>Mon, 19 Aug 2019 20:33:49 +0000</pubDate>
			<guid>https://quik2dde.ru/viewtopic.php?pid=2429#p2429</guid>
		</item>
		<item>
			<title><![CDATA[Советы]]></title>
			<link>https://quik2dde.ru/viewtopic.php?pid=2423#p2423</link>
			<description><![CDATA[<p>Обратился ко мне начинающий луа-программист с куском не рабочего кода.<br />Код написан вот в таком стиле, с кучей проверок, что само по себе не плохо, но как!<br /></p><div class="codebox"><pre><code> 
function fn(ds, signal)
  if ds ~= nil  then
   local index = ds:Size()
   local O, H, L, C = ds:O(index),  ds:O(index), ds:O(index), ds:O(index)
   if  O ~= 0 and H ~= 0 and L ~= 0 and C ~= 0 then
      if signal  == 0 then
        return (O + H + L + C)/4
      elseif signa &gt; 0 then
        if O &gt;= C then
          return O
        else
          return C
        end
      else
         if O &gt;= C then
          return C
        else
          return O
        end
      end
    else
      return 0
    end
  else
    return 0
  end
end</code></pre></div><p>Уровень вложенности блоков зашкаливает!<br />Читать такой код совсем не было желания, а на поиск оЧепятки или логической ошибки могло уйти много времени. Быстрее написать заново.<br />Так как это не первое подобное обращение, решил написать здесь пару советов.</p><p>1. При использовании документированных функций, обратите внимание на возвращаемый результат, в случае ошибки.<br />2. При вызове собственной функции, проверяйте передаваемые параметры <strong>до!</strong> вызова функции. Если какой то параметр не проходит проверку, то в вызове функции смысла нет.<br />3. Соблюдайте уровень вложенности логических блоков, если он &gt; 3, то код не читабельный, за поиск ошибки с вас попросят больше денег (время - деньги). Если по логике не выходит вложиться в эти рамки, то напишите дополнительную функцию и уберите лишнее ветвление в нее, тем самым вы понизите уровень вложенности.<br />4. Без нужды не используйте функции приведения типов - tostring, tonumber, это затратные по времени функции. Если сомневаетесь в типе данных, которые получаете из таблиц квик-а, проверьте их: message(&quot;price_type = type(item.price), 2)<br />5. Перед вычислениями нужно обработать все исключения, т.е. если для дальнейших расчетов один из параметров/переменных может привести к ошибке вычисления, то дальше считать нет смысла.<br />Вот так, примерно:<br /></p><div class="codebox"><pre><code>local function fn(ds, signal)
  -- signal по умолчанию число [-1; 1], его проверять не будем
  -- ds источник данных графика, на nil проверяется до вызова функции fn

  local index = ds:Size()
  -- вот эту проверку можно тоже сделать до вызова этой функции
  if index == 0 then reurn 0 end

  local O, H, L, C = ds:O(index),  ds:O(index), ds:O(index), ds:O(index)
  -- и эту проверку тоже, вдруг где-то еще понадобятся O, H, L, C
  if O == 0 or H == 0 or L == 0 or C == 0 then return 0 end

  -- все, исключения обработали, теперь к делу
  if signal  == 0 then
    -- вот тут второй уровень вложенности
    return (O + H + L + C)/4
  end
  
  if signal &gt; 0 then
    if O &gt;= C then
      -- это уже третий уровень вложенности, еще читабельно
      return O
    else
      return C
    end
  end
  -- убираем ветвление else, т.к. если до сюда дошло, то уже else (signal &lt; 0)
  if O &gt;= C then
   return C
  else
   return O
  end

end</code></pre></div><p>6. Доступ к глобальным луа-переменным медленнее, чем к локальным. Для ускорения выполнения алгоритма многие советуют вначале скрипта делать так:<br /></p><div class="codebox"><pre><code>local os_time = os.time
local floor = math.floor
local tm = os_time() -- это будет быстрее, чем вызвать функцию time() из глобальной таблицы os
local a = floor(3.14) -- и так быстрее</code></pre></div><p>чтобы не генерировать ошибки в дальнейшем, при копирования кода из одного скрипта в другой, можно и нужно делать так:<br /></p><div class="codebox"><pre><code>local os = os
local math = math
local tm = os.time()
local a = math.floor(3.14)</code></pre></div><p>это тоже быстро и будет работать, даже если вы где-то забудете объявить<br />local math = math<br />на вот такой объявление совет не распространяется <img src="https://quik2dde.ru/img/smilies/smile.png" width="15" height="15" alt="smile" /> тут никак не ошибешься при копировании.<br />local tonubber, tostring = tonubber, tostring<br />а подсветка синтаксиса останется.</p><p>В общем, успехов в начинаниях, и дополняйте раздел.</p>]]></description>
			<author><![CDATA[null@example.com (kalikazandr)]]></author>
			<pubDate>Thu, 01 Aug 2019 23:34:52 +0000</pubDate>
			<guid>https://quik2dde.ru/viewtopic.php?pid=2423#p2423</guid>
		</item>
	</channel>
</rss>
