Statistical Stock Scanner in Mathematica - wolfram-mathematica

my goal is to write an algorithm in Mathematica that will search for stocks whose current price is trading below or above 2 Standard Deviations of the Mean. I literally started to learn the program yesterday but I have been scouring the internet ever since for help. I have the code, but I am getting errors along the way. can someone help me?
Below is my current code
Today = Date[]
StartDate = Today-{0,3,0,0,0,0}
NYSEMem = FinancialData["NYSE","Members"]
CurrentPrice = FinancialData[NYSEMem,"Price"]
HistoricalPrice = FinancialData[NYSEMem,{{StartDate},{Today}}]
StandardDeviation$ = StandardDeviation[HistoricalPrice]
MeanPrice = Mean[HistoricalData]
SellSignal = [MeanPrice]-[StandardDeviation$]*2
BuySignal = [MeanPrice]+[StandardDeviation$]*2
If[CurrentPrice>SellSignal,"Sell",False]
If[CurrenPrice<BuySignal,"Buy",False]

Very brave to jump straight in the deep waters, but I'd suggest trying to learn the basics first. You say you've been "scouring the internet for help" but did you tried Mathematica's on-board documentation center? It has thousands pages of help, just one key press away.
Anyway as to your code, a few tips:
Don't end a variable with a $. Though
not wrong in principle, they are used
for system variables
The line SellSignal =
[MeanPrice]-[StandardDeviation$]*2, and the one following it contain function call brackets without corresponding function names. You probably don't intend to have these brackets there
The ,False part in If[CurrentPrice>SellSignal,"Sell",False] and the next line is unnecessary and can be deleted here
The earlier date calculation can be better done with the dedicated DatePlus function, which takes things like leap years etc. into account
You probably don't want to see all the output of all the lines. You may suppress output using ';' (which also acts to separate compound statements)
An asterisk for multiplication is unnecessary. A space will do, just as in math. a*b, a b, a 2, 2 a and 2a (without a space) are all correct multiplications.
The data you receive from some of the calls include both prices and dates. You are also trying to average the dates and find their standard deviation.
Though it is allowed to start a variable with an uppercase letter you better avoid doing that in order to prevent using Mathematica's own keywords (which all start with an uppercase letter).
I don't think your buy and sell signals are very smart. You might think of selling when prices are historically high, but you're doing it when they are above the historic low watermark.
Same for buying. Also, when current price is between your two signals the program provides conflicting advice.
You need a construction to repeat the calculations for every NYSE member
Some very very basic code to get you started:
StartDate = DatePlus[Date[], {-3, "Month"}];
NYSEMem = Select[FinancialData["NYSE", "Members"], (\[Not] StringMatchQ[#, ___ ~~
"^" ~~ ___] &)]; (* Throw away indices *)
Do[
currentPrice = Check[FinancialData[stock, "Price"], $Failed];
historicalPrice =
Check[FinancialData[stock, {StartDate, Date[]}], $Failed];
If[currentPrice == $Failed || historicalPrice == $Failed ||
currentPrice == Missing["NotAvailable"] ||
historicalPrice == Missing["NotAvailable"],
Continue[]]; (* Shamefully inadequate error handling *)
standardDeviationPrice = StandardDeviation[historicalPrice[[All, 2]]];
meanPrice = Mean[historicalPrice[[All, 2]]];
(* Mean of the second column of the data matrix *)
sellSignal = meanPrice + 2 standardDeviationPrice;
(* swapped + and - in these two lines, plug your own method here *)
buySignal = meanPrice - 2 standardDeviationPrice;
Print[stock, ": ",
If[currentPrice > sellSignal, "Sell",
If[currentPrice < buySignal, "Buy", "Neutral"]]];
, {stock, NYSEMem}
]
Please note that Stackoverflow is intended for people who have faithfully tried to do their best to do some research in the problems they encounter. I have the feeling that you don't really meet this criterion. My urgent request is: read some basic introductory text about Mathematica (for instance Getting started and Core Language Overview).

Here you have your program running:
Today = Date[];
StartDate = Today - {0, 3, 0, 0, 0, 0};
NYSEMem = FinancialData["NYSE", "Members"];
NYSEMem = NYSEMem[[1000 ;; 1001]];
CurrentPrice = FinancialData[#, "Price"] & /# NYSEMem;
HistoricalPrice = FinancialData[#, {StartDate, Today}] & /# NYSEMem;
StandardDeviation$ = StandardDeviation[#[[All, 2]]] & /# HistoricalPrice;
MeanPrice = Mean[#[[All, 2]]] & /# HistoricalPrice;
SellSignal = MeanPrice - StandardDeviation$*2
BuySignal = MeanPrice + StandardDeviation$*2
Do[
If[CurrentPrice[[i]] > SellSignal[[i]], Print["Sell ", NYSEMem[[i]]]];
If[CurrentPrice[[i]] < BuySignal[[i]], Print["Buy ", NYSEMem[[i]]]],
{i, 2}]
But please note I modified just the minimum to get it running without using idioms. This is not, by any standard, a good program. I did it just to let you play a little with it and learn some constructs.
HTH!

Related

Mathematica Do/For loop with "Delete" or "Drop" does not work

initlNum453 = List[];
num1 = 2;
(*Pt1, initial work to make initlNum full of good variables*)
algorithmicNum = 1;
For[i7 = 1, i7 <= (num1 + 1)^2, i7++,
AppendTo[initlNum453, algorithmicNum];
If[((algorithmicNum) == (num1 + 1)), algorithmicNum = 1,
algorithmicNum++];
];
(*Pt2, delete unneeded variables*)
deleteValue = 1;
Do[
Delete[initlNum453, deleteValue];
deleteValue = (deleteValue + num1 + 2);
, {num1 + 1}
]
Here's a snippet of the code I'm trying to make (it involves pseudo-automating Lagrange polynomials). It should be simple; the first part creates a series of numbers in a list, and then the second should be delete a particular section (e.g., the 1,4,7 if n=2).
For some reason, one of the following occurs:
No Error, but the elements in the list remains the same/no elements get deleted
Taking out the semicolon says that the "Tag Times in ___ is Protected"-- can someone explain what exactly this means?
When putting this into a Module, the error states that the expression .' cannot be used as a part specification. Use Key[.`] instead.
In any case, I don't understand why something as simple as this is just doesn't work on Mathematica. The "Delete" function works outside of a for/do loop, but doesn't inside-- can someone explain why or tell me what I did wrong?
Thanks for your help! I appreciate it!
You need to write something like
initlNum453 = Delete[initlNum453, deleteValue]

Sorting data by groups in Excel

So, I've looked around and tried to solve this on my own. This isn't an absolutely crucial question currently, I just want to know if it could be done.
So let's say I've got a list with some data that looks like
Date Location
01/24/14 H-12
01/25/14 BB-44
01/30/14 G-12
01/29/14 7A-55
01/28/14 NN-15
01/24/14 GG-47
What I want is to be able to sort the data by Location, but I don't want it to be the general way, otherwise I'll end up with 7A-55, BB-44, G-12, H-12, NN-15. I want the data to be sorted so that double letters and single letters are sorted together. E.G. it should be G-12, H-12, BB-44, NN-15, 7A-55 once everything has been sorted.
I've tried creating a custom list sort, but it doesn't work. the way intended. The custom list I tried was A-Z, AA-ZZ, 7A (items were listed out, but for saving space I wrote them like that).
Like I said, this isn't a particularly huge deal if it can't be done, it just would have made it a little easier.
Edit 1 Here is what I would like to be the output
Date Location
01/30/12 G-12
01/24/14 H-12
01/25/14 BB-44
01/24/14 GG-47
01/28/14 NN-15
01/29/14 7A-55
Edit
All of these worked in the regards i wanted to, although if I had to choose a favorite it would be the base 36 number conversion one. That was some real out-of-the-box thinking and the math geek in me appreciated it. Thanks everyone!
Well it works, but is a bit complex, so rather just for fun:
This UDF returns a value that can be used as sort key. It transforms the code into a four-digit base 36-number, i.e. using A-Z and 0-9 as symbols (like hex uses 0-9 and A-F). To get at your desired output, I literally put the symbols in this order, letters first (so "A" = 0 and "0" = 26).
(The missing 'digits' are filled up with zeros, which are in this case "A"s)
It works ;)
Public Function Base36Transform(r As Range) As Long
Dim s As String, c As String
Dim v
Dim i As Integer
Dim rv As Long
v = Split(r.Text, "-")
s1 = v(0)
s2 = v(1)
s = Right("A" & s1, 2) & Right("A" & s2, 2)
rv = 0
For i = 1 To Len(s)
c = Mid(s, Len(s) - i + 1, 1)
If c Like "#" Then
rv = rv + (Val(c) + 26) * (36 ^ (i - 1))
Else
' c is like "[A-Z]"
rv = rv + (Asc(c) - Asc("A")) * (36 ^ (i - 1))
End If
Next
Base36Transform = rv
End Function
Sorting is often a very creative process. VBA can ease up the process, but a little extension of the data will work just as well.
See my results:
The way I did it is by getting the length of each string, just to be safe. This is gotten by simply going =LEN(B2), dragged down.
Then I check if it starts with 7. If it does, assign 1, otherwise keep at 0. I used this formula: =(LEFT(B2,1)="7")*1, dragged down.
Now, my custom sort is this:
Now I might have gotten some things wrong here, or I might even have done overkill by going the Length column. However, the logic is pretty much what you're aiming for.
Hope this helps in a way! Let us know. :)
I am a little lazy here and assuming your data sits in Column A,B. You mightneed to adjust your range or the starting point of your list. But here's the code:
Sub sortttttt()
Dim rng As Range
Dim i As Integer
Range("B2").Activate
Do While Not IsEmpty(ActiveCell)
ActiveCell.Value = Len(ActiveCell.Value) & ActiveCell.Value
ActiveCell.Offset(1, 0).Activate
Loop
Set rng = Range("A1:B6")
rng.Sort Key1:=Range("B2"), Order1:=xlAscending, Header:=xlYes
Range("B2").Activate
Do While Not IsEmpty(ActiveCell)
ActiveCell.Value = Right(ActiveCell.Value, Len(ActiveCell.Value) - 1)
ActiveCell.Offset(1, 0).Activate
Loop
End Sub
Assuming your data is in columns B:C with labels in Row1 and no intervening blank rows, add a column with:
=IF(ISNUMBER(VALUE(LEFT(C2))),3,IF(FIND("-",C2)>2,2,1))
in D1 copied down to suit and sort ascending Location within sort ascending of the added column.

How to disable case sensitivity in Mathematica functions?

I want to make mathematica insensitive to the functions first capital letter. For example, it accepts both "Plot" and "plot" as plotting function.
I agree with george's sentiment: "You don't want to do that." It is common practice to start user Symbols with lowercase letters which both identifies them and prevents collisions with built-ins. Nevertheless you can do this in several ways. One is just to create aliases as george also suggested, e.g.
plot = Plot;
sin = Sin;
plot[sin[x], {x, 0, 6}]
This has the advantage of working even in packages because it does not rely on the Front End. However, because these are not true aliases it will fail in some cases, e.g.:
evaluate = Evaluate;
Hold[evaluate[2 + 2]]
Hold[evaluate[2 + 2]]
Whereas the "real" function behaves like this:
Hold[Evaluate[2 + 2]]
Hold[4]
To get complete equivalence, though only in the Front End, you can use $PreRead. (Example.) You will need to build a list of rules that replace the string form of each lowercase Symbol with the uppercase string. I shall do that only for all Symbols in the System` context.
With[{rules = Thread[ToLowerCase[#] -> #] & # Names["System`*"]},
$PreRead = # /. rules &
];
Now both of these examples work:
plot[sin[x], {x, 0, 6}]
hold[evaluate[2 + 2], 3 + 4]
The latter producing:
Hold[4, 3 + 4]
This is not a direct answer to your question and I strongly advise you against redefining Mathematica functions just for the sake of the letter-case.
Nevertheless, have you seen that there is an option Match case in command completion when you go to Edit -> Preferences -> Interface?
If you turn this off, then you can type plot in the notebook and you get the correct Plot as suggestion from the autocompletion. You only have to hit enter and the correct command is inserted.

Cake Comparison Algorithm

This is literally about comparing cakes. My friend is having a cupcake party with the goal of determining the best cupcakery in Manhattan. Actually, it's much more ambitious than that. Read on.
There are 27 bakeries, and 19 people attending (with maybe one or two no-shows). There will be 4 cupcakes from each bakery, if possible including the staples -- vanilla, chocolate, and red velvet -- and rounding out the 4 with wildcard flavors. There are 4 attributes on which to rate the cupcakes: flavor, moistness, presentation (prettiness), and general goodness. People will provide ratings on a 5-point scale for each attribute for each cupcake they sample. Finally, each cupcake can be cut into 4 or 5 pieces.
The question is: what is a procedure for coming up with a statistically meaningful ranking of the bakeries for each attribute, and for each flavor (treating "wildcard" as a flavor)? Specifically, we want to rank the bakeries 8 times: for each flavor we want to rank the bakeries by goodness (goodness being one of the attributes), and for each attribute we want to rank the bakeries across all flavors (ie, independent of flavor, ie, aggregating over all flavors). The grand prize goes to the top-ranked bakery for the goodness attribute.
Bonus points for generalizing this, of course.
This is happening in about 12 hours so I'll post as an answer what we ended up doing if no one answers in the meantime.
PS: Here's the post-party blog post about it: http://gracenotesnyc.com/2009/08/05/gracenotes-nycs-cupcake-cagematch-the-sweetest-battle-ever/
Here's what we ended up doing. I made a huge table to collect everyone's ratings at http://etherpad.com/sugarorgy (Revision 25, just in case it gets vandalized with me adding this public link to it) and then used the following Perl script to parse the data into a CSV file:
#!/usr/bin/env perl
# Grabs the cupcake data from etherpad and parses it into a CSV file.
use LWP::Simple qw(get);
$content = get("http://etherpad.com/ep/pad/export/sugarorgy/latest?format=txt");
$content =~ s/^.*BEGIN_MAGIC\s*//s;
$content =~ s/END_MAGIC.*$//s;
$bakery = "none";
for $line (split('\n', $content)) {
next if $line =~ /sar kri and deb/;
if ($line =~ s/bakery\s+(\w+)//) { $bakery = $1; }
$line =~ s/\([^\)]*\)//g; # strip out stuff in parens.
$line =~ s/^\s+(\w)(\w)/$1 $2/;
$line =~ s/\-/\-1/g;
$line =~ s/^\s+//;
$line =~ s/\s+$//;
$line =~ s/\s+/\,/g;
print "$bakery,$line\n";
}
Then I did the averaging and whatnot in Mathematica:
data = Import["!~/svn/sugar.pl", "CSV"];
(* return a bakery's list of ratings for the given type of cupcake *)
tratings[bak_, t_] := Select[Drop[First#Select[data,
#[[1]]==bak && #[[2]]==t && #[[3]]=="g" &], 3], #!=-1&]
(* return a bakery's list of ratings for the given cupcake attribute *)
aratings[bak_, a_] := Select[Flatten[Drop[#,3]& /#
Select[data, #[[1]]==bak && #[[3]]==a&]], #!=-1&]
(* overall rating for a bakery *)
oratings[bak_] := Join ## (tratings[bak, #] & /# {"V", "C", "R", "W"})
bakeries = Union#data[[All, 1]]
SortBy[{#, oratings##, Round[Mean#oratings[#], .01]}& /# bakeries, -#[[3]]&]
The results are at the bottom of http://etherpad.com/sugarorgy.
Perhaps reading about voting systems will be helpful. PS: don't take whatever is written on Wikipedia as "good fish". I have found factual errors in advanced topics there.
Break the problem up into sub-problems.
What's the value of a cupcake? A basic approach is "the average of the scores." A slightly more robust approach may be "the weighted average of the scores." But there may be complications beyond that... a cupcake with 3 goodness and 3 flavor may be 'better' than one with 5 flavor and 1 goodness, even if flavor and goodness have equal weight (IOW, a low score may have a disproportionate effect).
Make up some sample cupcake scores (specifics! Cover the normal scenarios and a couple weird ones), and estimate what you think a reasonable "overall" score would be if you had an ideal algorithm. Then, use that data to reverse engineer the algorithm.
For example, a cupcake with goodness 4, flavor 3, presentation 1 and moistness 4 might deserve a 4 overall, while one with goodness 4, flavor 2, presentation 5, and moistness 4 might only rate a 3.
Next, do the same thing for the bakery. Given a set of cupcakes with a range of scores, what would an appropriate rating be? Then, figure out the function that will give you that data.
The "goodness" ranking seems a bit odd, as it seems like it's a general rating, and so having it in there is already the overall score, so why calculate an overall score?
If you had time to work with this, I'd always suggest capturing the raw data, and using that as a basis to do more detailed analysis, but I don't think that's really relevant here.
Perhaps this is too general for you, but this type of problem can be approached using Conjoint Analysis (link text). A R package for implementing this is bayesm(link text).
If you can write SQL, you could make a little database and write some queries. It should not be that difficult.
e.g. select sum(score) / count(score) as finalscore, bakery, flavour from tables where group by bakery, flavour

Mathematica Downvalue Lhs

Does anybody know if there is a built-in function in Mathematica for getting the lhs of downvalue rules (without any holding)? I know how to write the code to do it, but it seems basic enough for a built-in
For example:
a[1]=2;
a[2]=3;
BuiltInIDoNotKnowOf[a] returns {1,2}
This is like keys() in Perl and Python and other languages that have built in support for hashes (aka dictionaries). As your example illustrates, Mathematica supports hashes without any special syntax. Just say a[1] = 2 and you have a hash. [1]
To get the keys of a hash, I recommend adding this to your init.m or your personal utilities library:
keys[f_] := DownValues[f][[All,1,1,1]] (* Keys of a hash/dictionary. *)
(Or the following pure function version is supposedly slightly faster:
keys = DownValues[#][[All,1,1,1]]&; (* Keys of a hash/dictionary. *)
)
Either way, keys[a] now returns what you want. (You can get the values of the hash with a /# keys[a].) If you want to allow for higher arity hashes, like a[1,2]=5; a[3,4]=6 then you can use this:
SetAttributes[removeHead, {HoldAll}];
removeHead[h_[args___]] := {args}
keys[f_] := removeHead ### DownValues[f][[All,1]]
Which returns {{1,2}, {3,4}}. (In that case you can get the hash values with a ### keys[a].)
Note that DownValues by default sorts the keys, which is probably not a good idea since at best it takes extra time. If you want the keys sorted you can just do Sort#keys[f]. So I would actually recommend this version:
keys = DownValues[#,Sort->False][[All,1,1,1]]&;
Interestingly, there is no mention of the Sort option in the DownValues documention. I found out about it from an old post from Daniel Lichtblau of Wolfram Research. (I confirmed that it still works in the current version (7.0) of Mathematica.)
Footnotes:
[1] What's really handy is that you can mix and match that with function definitions. Like:
fib[0] = 1;
fib[1] = 1;
fib[n_] := fib[n-1] + fib[n-2]
You can then add memoization by changing that last line to
fib[n_] := fib[n] = fib[n-1] + fib[n-2]
which says to cache the answer for all subsequent calls.
This seems to work; not sure how useful it is, though:
a[1] = 2
a[2] = 3
a[3] = 5
a[6] = 8
Part[DownValues[a], All, 1, 1, 1]

Resources