Advertisement
Guest User

Untitled

a guest
Oct 25th, 2014
177
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 16.77 KB | None | 0 0
  1. program Mercher;
  2. {$I SimbaExt/SimbaExt.simba}
  3.  
  4. const  
  5.   {Only Required for First-Time Run or backchecking}
  6.  
  7.   startCash = 1000000;
  8.  
  9.   {BackCheck Settings - Only required if testing algorithm settings}
  10.  
  11.   backCheck = False;
  12.   simDays = 100;
  13.  
  14.   {Algorithm Settings - Experimentally Determined - Changes allowed if you know what they do}
  15.  
  16.   ScoreRange = 3;
  17.   MACDDays = 3;
  18.   RSIDays = 3;
  19.   StoDays1 = 3;
  20.   StoDays2 = 3;
  21.   AroonDays = 3;
  22.   BollDays = 4;
  23.   PickDays = 15;
  24.   PickPercent = 5;
  25.   BuyPercentage = 25;
  26.  
  27.   {Do NOT Touch Below Here}
  28.  
  29.   ALGO_BUY = 1;
  30.   ALGO_HOLD = 0;
  31.   ALGO_SELL = - 1;
  32.  
  33. type
  34.   TItemInfo = record
  35.     Prices, MACDScore, RSIScore, StoScore, ArScore, BolScore, TotScore: TIntArray;
  36.     Name: string;
  37.     TradeLimit, AmountOwned, Bought, GoodTrades, Trades: Integer;
  38.   end;
  39.   TItemInfoArray = array of TItemInfo;
  40.  
  41. type
  42.   TPortfolio = record
  43.     Items: TItemInfoArray;
  44.     Cash: Integer;
  45.   end;
  46.  
  47. function pickItems(currentDay, range, limitFrac: Integer; theItem: TItemInfo): Integer;
  48. var
  49.   i, h, MinP, MaxP: Integer;
  50.   avg, Score: Extended;
  51.   tempA: TIntArray;
  52. begin
  53.   Result := ALGO_BUY;
  54.   if currentDay - (range - 1) < 0 then
  55.     Exit;
  56.   setLength(tempA, range);
  57.   tempA := theItem.Prices.Slice(currentDay - (range - 1), currentDay);
  58.   se.MinMaxTIA(tempA, MinP, MaxP);
  59.   avg := tempA.Mean();
  60.   Score := (MaxP - MinP) / Avg;
  61.   if Score < (limitFrac / 100) then
  62.     Result := ALGO_SELL;
  63. end;
  64.  
  65. function MACD(currentDay, range: Integer; theItem: TItemInfo): Integer;
  66. var
  67.   i, h, x, y: Int32;
  68.   avg, comp: Extended;
  69.   tempA: TIntegerArray;
  70. begin
  71.   if (range - 1) > currentDay then
  72.   begin
  73.     Result := ALGO_HOLD;
  74.     Exit;
  75.   end;
  76.   setLength(tempA, range);
  77.   tempA := theItem.Prices.slice(currentDay - (range - 1), currentDay);
  78.   avg := TempA.mean();
  79.   comp := avg - theItem.Prices[currentDay];
  80.   if comp > 0 then
  81.     Result := ALGO_SELL;
  82.   if comp = 0 then
  83.     Result := ALGO_HOLD;
  84.   if comp < 0 then
  85.     Result := ALGO_BUY;
  86. end;
  87.  
  88. function doRSI(currentDay, range, Upper, Lower: Integer; theItem: TItemInfo): Integer;
  89. var
  90.   i, h, x, change, y: Integer;
  91.   Gains, Losses : TIntegerArray;
  92.   avgG, avgL, RS, RSI: Extended;
  93. begin
  94.   if (range - 2) > currentDay then
  95.   begin
  96.     Result := ALGO_HOLD;
  97.     Exit;
  98.   end;
  99.   SetLength(Gains, range);
  100.   SetLength(Losses, range);
  101.   x := (currentDay - (range - 1));
  102.   for i := (currentDay - (range - 1)) to currentDay do
  103.   begin
  104.     change := theItem.Prices[i] - theItem.Prices[i - 1];
  105.     if change > 0 then
  106.     begin
  107.       Gains[i - x] := change;
  108.       Losses[i - x] := 0;
  109.     end
  110.     else if change < 0 then
  111.     begin
  112.       Losses[i - x] := 0 - change;
  113.       Gains[i - x] := 0;
  114.     end;
  115.   end;
  116.   avgG := Gains.mean();
  117.   avgL := Losses.mean();
  118.   if avgL = 0 then
  119.     RSI := 100
  120.   else
  121.   begin
  122.     RS := avgG / avgL;
  123.     RSI := 100 - (100 / (1 + RS))
  124.   end;
  125.   if RSI > Upper then
  126.     Result := ALGO_SELL
  127.   else if RSI < Lower then
  128.     Result := ALGO_BUY
  129.   else
  130.     Result := ALGO_HOLD;
  131. end;
  132.  
  133. function doSto(currentDay, range1, range2: Integer; theItem: TItemInfo): Integer;
  134. var
  135.   i, h, x: Integer;
  136.   minP, maxP: Integer;
  137.   d: Extended;
  138.   k: TExtArray;
  139.   tempA: TIntArray;
  140. begin
  141.   if (currentDay - (range1 - 1) - (range2 - 1)) < 0 then
  142.   begin
  143.     Result := ALGO_HOLD;
  144.     Exit;
  145.   end;
  146.   setLength(k, range2);
  147.   setLength(tempA, range1);
  148.   x := currentDay - (range2 - 1);
  149.   for i := (currentDay - (range2 - 1)) to currentDay do
  150.   begin
  151.     tempA := theItem.Prices.slice(i - (range1 - 1), i);
  152.     se.MinMaxTIA(tempA, minP, maxP);
  153.     if (maxP - minP) <= 0 then
  154.       k[i - x] := 100
  155.     else
  156.       k[i - x] := 100 * ((tempA[high(tempA)] - minP) / (maxP - minP));
  157.   end;
  158.   d := K.mean();
  159.   h := high(k);
  160.   if d > k[h] then
  161.     Result := ALGO_SELL;
  162.   if d < k[h] then
  163.     Result := ALGO_BUY;
  164.   if d = k[h] then
  165.     Result := ALGO_HOLD;
  166. end;
  167.  
  168. function doAroon(currentDay, range: Integer; theItem: TItemInfo): Integer;
  169. var
  170.   i, h, y, x, maxDay, minDay: Integer;
  171.   upDir, downDir, Aroon: Extended;
  172.   tempA: TIntegerArray;
  173. begin
  174.   if currentDay - (range - 1) < 0 then
  175.   begin
  176.     Result := ALGO_HOLD;
  177.     Exit;
  178.   end;
  179.   SetLength(tempA, range);
  180.   tempA := theItem.Prices.Slice(currentDay, currentDay - (range - 1), - 1);
  181.   maxDay := TempA.argMax();
  182.   minDay := TempA.argMin();
  183.   upDir := 100 * (((range - 1) - MaxDay) / (range - 1));
  184.   downDir := 100 * (((range - 1) - MinDay) / (range - 1));
  185.   Aroon := upDir - downDir;
  186.   if Aroon > 0 then
  187.     Result := ALGO_BUY;
  188.   if Aroon < 0 then
  189.     Result := ALGO_SELL;
  190.   if Aroon = 0 then
  191.     Result := ALGO_HOLD;
  192. end;
  193.  
  194. function Bollinger(currentDay, range, percentClose: Integer; SDMultiplier: Extended; theItem: TItemInfo): Integer;
  195. var
  196.   i, h, x: Integer;
  197.   tempA: TIntArray;
  198.   avg, SD, SDMult: Extended;
  199.   upper, lower: TExtArray;
  200.   touchUpper, touchLower: array of Boolean;
  201. begin
  202.   if currentDay - range < 0 then
  203.   begin
  204.     Result := ALGO_HOLD;
  205.     Exit;
  206.   end;
  207.   SetLength(Upper, 2);
  208.   SetLength(Lower, 2);
  209.   SetLength(TouchUpper, 2);
  210.   SetLength(TouchLower, 2);
  211.   SetLength(tempA, range);
  212.   x := 0;
  213.   for i := 1 downto 0 do
  214.   begin
  215.     tempA := theItem.Prices.slice(currentDay - i - (range - 1), currentDay - i);
  216.     avg := tempA.Mean();
  217.     SD := tempA.Stdev();
  218.     SDMult := SD * SDMultiplier;
  219.     Upper[x] := avg + SDMult;
  220.     Lower[x] := avg - SDMult;
  221.     touchUpper[x] := (theItem.Prices[currentDay - i] >= (Upper[x] * (1 - (percentClose / 100))));
  222.     touchLower[x] := (theItem.Prices[currentDay - i] <= (Lower[x] * (1 + (percentClose / 100))));
  223.     inc(x);
  224.   end;
  225.   if (touchLower[0] and (not touchLower[1])) then
  226.   begin
  227.     Result := ALGO_BUY;
  228.     Exit;
  229.   end;
  230.   if (touchUpper[0] and (not touchUpper[1])) then
  231.   begin
  232.     Result := ALGO_SELL;
  233.     Exit;
  234.   end;
  235.   Result := ALGO_HOLD;
  236. end;
  237.  
  238. function addResults(currentDay: Integer; theItem: TItemInfo): Integer;
  239. begin
  240.   Result := theItem.MACDScore[currentDay] + theItem.RSIScore[currentDay] + theItem.StoScore[currentDay] + theItem.ArScore[currentDay] + theItem.BolScore[currentDay];
  241. end;
  242.  
  243. function ScoreItems(currentDay, range: Integer; totalScores : TIntArray): Integer;
  244. var
  245.   tempScore: TIntArray;
  246. begin
  247.   setLength(tempScore, range);
  248.   tempScore := TotalScores.Slice(currentDay - (range - 1), currentDay);
  249.   Result := se.SumTIA(tempScore);
  250. end;
  251.  
  252. procedure handleBuys(var Portfolio: TPortfolio; currentDay, percentBuy: Integer);
  253. var
  254.   i, h, toBuy, inventory, startCash, theScore: Integer;
  255.   purchased: Boolean;
  256. begin
  257.   h := high(portfolio.Items);
  258.   startCash := Portfolio.Cash;
  259.   for i := 0 to h do
  260.   begin
  261.     if (ScoreRange > 0) and (currentDay - (scoreRange - 1) >= 0) then
  262.       theScore := ScoreItems(currentDay, scoreRange, Portfolio.Items[i].totScore)
  263.     else
  264.       theScore := 1;
  265.     if (Portfolio.Items[i].TotScore[CurrentDay] > ALGO_HOLD) and (Portfolio.Items[i].AmountOwned = 0) and (theScore >= 0) then
  266.     begin
  267.       toBuy := trunc((startCash * (percentBuy / 100)) / Portfolio.Items[i].Prices[currentDay]);
  268.       if toBuy > Portfolio.Items[i].TradeLimit then
  269.         toBuy := Portfolio.Items[i].TradeLimit;
  270.       if toBuy * Portfolio.Items[i].Prices[currentDay] > Portfolio.Cash then
  271.         toBuy := trunc(Portfolio.Cash / Portfolio.Items[i].Prices[currentDay]);
  272.       Portfolio.Items[i].AmountOwned := toBuy;
  273.       Portfolio.Cash := Portfolio.Cash - (toBuy * Portfolio.Items[i].Prices[currentDay]);
  274.       Portfolio.Items[i].Bought := Portfolio.Items[i].Prices[currentDay];
  275.     end;
  276.     if ((Portfolio.Items[i].TotScore[CurrentDay] < ALGO_HOLD) and (Portfolio.Items[i].AmountOwned > 0)) or (currentDay = simDays) then
  277.     begin
  278.       Portfolio.Cash := Portfolio.Cash + (Portfolio.Items[i].AmountOwned * Portfolio.Items[i].Prices[currentDay]);
  279.       Portfolio.Items[i].AmountOwned := 0;
  280.       inc(Portfolio.Items[i].Trades);
  281.       if Portfolio.Items[i].Prices[currentDay] >= Portfolio.Items[i].Bought then
  282.         inc(Portfolio.Items[i].GoodTrades);
  283.       Portfolio.Items[i].Bought := 0;
  284.     end;
  285.   end;
  286. end;
  287.  
  288. function RS_GetPricesOf(Item: string; numSamples: Int32 = 100): TItemInfo;
  289. var
  290.   i, date, value, exchangeLim: Int32;
  291.   Page, fullPage, str: string;
  292.   items, list: TStringArray;
  293.  
  294. function FindPriceList(const text: string): string;
  295. var
  296.   p: Integer;
  297. begin
  298.   p := pos('<p class="GEdataprices"', text);
  299.   result := copy(text, p, length(text) - p);
  300. end;
  301.  
  302. begin
  303.   item := Replace(item, ' ', '_', [rfReplaceAll]);
  304.   fullPage := GetPage('http://runescape.wikia.com/wiki/Exchange:' + Item);
  305.   page := FindPriceList(fullPage);
  306.   Result.TradeLimit := StrtoInt(Between('data-limit="', '" style="display:none">', Page));
  307.   Result.Name := Item;
  308.   items := Explode(',', Between('>', '</p>', page));
  309.   if numSamples > Length(items) then
  310.     WriteLn(Format('[Hint] NumSamples overflow: Could only gather %d samples', [High(items)]));
  311.   for i := Max(High(items) - numSamples, 0) to High(items) do
  312.   begin
  313.     list := Explode(':', items[i]);
  314.     if length(list) >= 2 then
  315.     begin
  316.       value := list[1].GetNumbers()[0];
  317.       Result.Prices.Append(value);
  318.     end;
  319.   end;
  320. end;
  321.  
  322. function RS_GetTopItems100(): TStringArray;
  323. var
  324.   i: Int32;
  325.   Str: string;
  326.  
  327. function ForwardStrTo(const text, tag: string; After: Boolean = False): string;
  328. var
  329.   p: Integer;
  330. begin
  331.   p := pos(tag, text);
  332.   if After then
  333.     Result := copy(text, p + length(tag), length(text) - p - length(tag) + 1)
  334.   else
  335.     Result := copy(text, p, length(text) - p);
  336. end;
  337.  
  338. begin
  339.   Str := GetPage('http://services.runescape.com/m=itemdb_rs/top100?list=0&scale=2');
  340.   Str := Between('<th colspan="4">Trade Count</th>', '</tbody>', Str);
  341.   Str := ForwardStrTo(Str, '<tbody>');
  342.   Result := MultiBetween(str, '<img src="http://services.runescape.com/', '">');
  343.   for i := 0 to High(Result) do
  344.   begin
  345.     Result[i] := ForwardStrTo(Result[i], 'alt="', True);
  346.   end;
  347. end;
  348.  
  349. procedure SetupINIFile;
  350. var
  351.   firstRun: Boolean;
  352.   Strings: TStringArray;
  353.   i: Integer;
  354. begin
  355.   firstRun := (messageBox('Is this your first time running this script?', 'Setup', 4) = 6);
  356.   if firstRun then
  357.   begin
  358.     SetLength(Strings, 100);
  359.     Strings := RS_GetTopItems100();
  360.     WriteINI('Portfolio', 'Cash', toStr(StartCash), ScriptPath + 'MerchantSettings');
  361.     WriteINI('Portfolio', 'Item Length', toStr(length(Strings)), ScriptPath + 'MerchantSettings');
  362.     for i := 0 to high(Strings) do
  363.     begin
  364.       WriteINI('Portfolio', toStr(i), Strings[i], ScriptPath + 'MerchantSettings');
  365.       WriteINI(Strings[i], 'Bought', '0', ScriptPath + 'MerchantSettings');
  366.       WriteINI(Strings[i], 'Amount', '0', ScriptPath + 'MerchantSettings');
  367.     end;
  368.   end;
  369. end;
  370.  
  371. function INIGetStrings() : TStringArray;
  372. var
  373.   i, h: Integer;
  374. begin
  375.   //SetLength(Result, strToInt(ReadINI('Portfolio', 'Item Length', ScriptPath + 'MerchantSettings')));
  376.   h := strToInt(ReadINI('Portfolio', 'Item Length', ScriptPath + 'MerchantSettings'));
  377.   for i := 0 to h-1 do
  378.     Result.Append(ReadINI('Portfolio', toStr(i), ScriptPath + 'MerchantSettings'));
  379. end;
  380.  
  381. function INIGetCash() : Integer;
  382. begin
  383.   Result := strToInt(ReadINI('Portfolio', 'Cash', ScriptPath + 'MerchantSettings'));
  384. end;
  385.  
  386. procedure doRecommend(thePortfolio: TPortfolio; day, percentBuy: Integer);
  387. var
  388.   i, h, toBuy, inventory, theScore, cashStart: Integer;
  389.   purchased: Boolean;
  390.   TTIA : TIntArray;
  391. begin
  392.   h := high(thePortfolio.Items);
  393.   CashStart := thePortfolio.Cash;
  394.   for i := 0 to h do
  395.   begin
  396.     //writeln('Item: ' + toStr(theportfolio.Items[i]));
  397.     //Writeln('Day: ' + toStr(Day) + ', High Prices: ' + toStr(high(thePortfolio.Items[i].Prices)));
  398.     TTIA := thePortfolio.Items[i].TotScore;
  399.     theScore := ScoreItems(Day, scoreRange, TTIA);
  400.     if (thePortfolio.Items[i].TotScore[day] > ALGO_HOLD) and (thePortfolio.Items[i].AmountOwned = 0) and (theScore >= 0) then
  401.     begin
  402.       toBuy := trunc((CashStart * (percentBuy / 100)) / thePortfolio.Items[i].Prices[Day]);
  403.       if toBuy > thePortfolio.Items[i].TradeLimit then
  404.         toBuy := thePortfolio.Items[i].TradeLimit;
  405.       if toBuy * thePortfolio.Items[i].Prices[Day] > thePortfolio.Cash then
  406.         toBuy := trunc(thePortfolio.Cash / thePortfolio.Items[i].Prices[Day]);
  407.       if toBuy = 0 then continue;
  408.       if (messageBox('Would you like to buy ' + toStr(toBuy) + ' ' + thePortfolio.Items[i].Name + ' for ' + toStr(thePortfolio.Items[i].Prices[day]) + 'gp each, a total of ' + tostr(toBuy * thePortfolio.Items[i].Prices[Day]) + '?', 'Buy?', 4) = 6) then
  409.       begin
  410.         thePortfolio.Items[i].AmountOwned := toBuy;
  411.         thePortfolio.Cash := thePortfolio.Cash - (toBuy * thePortfolio.Items[i].Prices[Day]);
  412.         thePortfolio.Items[i].Bought := thePortfolio.Items[i].Prices[Day];
  413.         WriteINI(thePortfolio.Items[i].Name, 'Amount', toStr(toBuy), ScriptPath + 'MerchantSettings');
  414.         WriteINI(thePortfolio.Items[i].Name, 'Bought', toStr(thePortfolio.Items[i].Prices[Day]), ScriptPath + 'MerchantSettings');
  415.       end;
  416.     end;
  417.     if ((thePortfolio.Items[i].TotScore[Day] < ALGO_HOLD) and (thePortfolio.Items[i].AmountOwned > 0)) then
  418.     begin
  419.       if (messageBox('Would you like to sell ' + toStr(toBuy) + ' ' + thePortfolio.Items[i].Name + ' for ' + toStr(thePortfolio.Items[i].Prices[day]) + 'gp each, a total of ' + tostr(thePortfolio.Items[i].AmountOwned * thePortfolio.Items[i].Prices[Day]) + '?', 'Sell?', 4) = 6) then
  420.       begin
  421.         thePortfolio.Cash := thePortfolio.Cash + (thePortfolio.Items[i].AmountOwned * thePortfolio.Items[i].Prices[Day]);
  422.         thePortfolio.Items[i].AmountOwned := 0;
  423.         inc(thePortfolio.Items[i].Trades);
  424.         if thePortfolio.Items[i].Prices[Day] >= thePortfolio.Items[i].Bought then
  425.           inc(thePortfolio.Items[i].GoodTrades);
  426.         thePortfolio.Items[i].Bought := 0;
  427.         WriteINI(thePortfolio.Items[i].Name, 'Amount', '0', ScriptPath + 'MerchantSettings');
  428.         WriteINI(thePortfolio.Items[i].Name, 'Bought', '0', ScriptPath + 'MerchantSettings');
  429.       end;
  430.     end;
  431.   end;
  432.   WriteINI('Portfolio', 'Cash', toStr(thePortfolio.Cash), ScriptPath + 'MerchantSettings');
  433. end;
  434.  
  435. var
  436.   Strings: TStringArray;
  437.   i, j, days, res: Integer;
  438.   myPortfolio, tempPort: TPortfolio;
  439.  
  440. begin
  441.   ClearDebug();
  442.  
  443.   if not BackCheck then SetupINIFile();
  444.   if BackCheck then Strings := RS_GetTopItems100() else Strings := INIGetStrings();
  445.   if BackCheck then Days := simDays else Days := 30;
  446.   if BackCheck then myPortfolio.Cash := startCash else myPortfolio.Cash := INIGetCash();
  447.  
  448.   SetLength(myPortfolio.Items, Length(Strings));
  449.   Writeln('Getting Prices: Be Patient');
  450.   for i := 0 to high(Strings) do
  451.     begin
  452.     myPortfolio.Items[i] := RS_GetPricesOf(Strings[i], Days);
  453.     if not Backcheck then
  454.     begin
  455.       myPortfolio.Items[i].Name := Replace(myPortfolio.Items[i].Name, '_', ' ', [rfReplaceAll]);
  456.       myPortfolio.Items[i].AmountOwned := strToInt(ReadINI(myPortfolio.Items[i].Name, 'Amount', ScriptPath + 'MerchantSettings'));
  457.           myPortfolio.Items[i].Bought := strToInt(ReadINI(myPortfolio.Items[i].Name, 'Bought', ScriptPath + 'MerchantSettings'));
  458.     end;
  459.       //myPortfolio.Items[i].GoodTrades :=
  460.       //myPortfolio.Items[i].Trades :=
  461.     end;
  462.   for j := 0 to high(myPortfolio.Items) do
  463.   begin
  464.       if myPortfolio.Items[j].Name = '' then Continue;
  465.     setLength(myPortfolio.Items[j].MACDScore, Days + 1);
  466.     setLength(myPortfolio.Items[j].RSIScore, Days + 1);
  467.     setLength(myPortfolio.Items[j].StoScore, Days + 1);
  468.     setLength(myPortfolio.Items[j].ArScore, Days + 1);
  469.     setLength(myPortfolio.Items[j].BolScore, Days + 1);
  470.     setLength(myPortfolio.Items[j].TotScore, Days + 1);
  471.     for i := 0 to Days do
  472.     begin
  473.       if pickItems(i, PickDays, PickPercent, myPortfolio.Items[j]) > ALGO_HOLD then
  474.       begin
  475.         myPortfolio.Items[j].MACDScore[i] := MACD(i, MACDDays, myPortfolio.Items[j]);
  476.         myPortfolio.Items[j].RSIScore[i] := doRSI(i, RSIDays, 70, 30, myPortfolio.Items[j]);
  477.         myPortfolio.Items[j].StoScore[i] := doSto(i, StoDays1, StoDays2, myPortfolio.Items[j]);
  478.         myPortfolio.Items[j].ArScore[i] := doAroon(i, AroonDays, myPortfolio.Items[j]);
  479.         myPortfolio.Items[j].BolScore[i] := Bollinger(i, BollDays, 1, 1.9, myPortfolio.Items[j]);
  480.         myPortfolio.Items[j].TotScore[i] := addResults(i, myPortfolio.Items[j]);
  481.       end else
  482.       begin
  483.         myPortfolio.Items[j].MACDScore[i] := 0;
  484.         myPortfolio.Items[j].RSIScore[i] := 0;
  485.         myPortfolio.Items[j].StoScore[i] := 0;
  486.         myPortfolio.Items[j].ArScore[i] := 0;
  487.         myPortfolio.Items[j].BolScore[i] := 0;
  488.         myPortfolio.Items[j].TotScore[i] := 0;
  489.       end;
  490.     end;
  491.     end;
  492.   if BackCheck then
  493.   begin
  494.     for i := 0 to simDays do
  495.       handleBuys(myPortfolio, i, buyPercentage);
  496.     writeln('Value: ' + toStr(myPortfolio.Cash));
  497.   end else
  498.   begin
  499.     tempPort := myPortfolio;
  500.     doRecommend(tempPort, high(tempPort.Items[0].Prices), buyPercentage);
  501.   end;
  502. end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement