How to create list order message in QuickFix/J - fix-protocol

I'm trying to generate a "list orders" (forex orders) to be executed by my TargetCompID with QuickFix/J lib.
If I correctly understand the FIX message standard, my message must have the following fields (I've put my values in parenthesis):
Header part
8 BeginString (FIX.4.4)
9 BodyLength (will be computed and provided by quickfixj when sending)
35 MsgType (E = NewOrderList)
34 MsgSeqNum (will be computed and provided by quickfixj whend sending)
49 SenderCompId (that's me)
52 SendingTime (will be computed and provided by quickfixj when sending)
56 TargetCompId (that's my counterparty which will execute my FX orders)
Then body part
66 ListId (uniq id computed)
68 ToNoOrders (count of my orders into list)
73 NoOrders (same count value as I will generate a complete list of order at once)
Then repeat list of following fields (one list fields per order in my list):
11 ClOrdId (my order id)
67 ListSeqNo (index of the order into my list: from 1 to N; N = ToNoOrders = NoOrders)
... several others fields as 15 (currency), 120 (SettlCurrency)
To do that I've done (in java / quickfixj):
Message message = new Message();
Header header = message.getHeader();
header.setField(new BeginString("FIX.4.4"));
header.setField(new MsgType("E"));
header.setField(new SenderCompID("it's me"));
header.setField(new TargetCompID("my counterparty"));
message.setField(new ListID(_fixListId));
message.setField(new TotNoOrders(_list.size()));
message.setField(new NoOrders(_list.size()));
int idx = 0;
for (Order order : _list) {
message.setField(new ClOrdID(order.getId()));
message.setField(new ListSeqNo(++idx));
//message.setField(.... other fields to add to describe my order)
}
But doing this, in the callback function toApp of my quickfixj application ("This is a callback for application messages that you are being sent to a counterparty"), displaying the message in parameter (syso(message)) shows that only one order is inside my message, and it's the last oder I've put.
It seems they are some "group" we can create in QuickFixJ, and we can add several groups inside the same message. But there are a tons of kind of group, and I don't figure out what is the group appropriate for my "list order", if any? I see that there is a subclass of Message which is NewOrderList (it's my MsgType = E), but it's not a "group"; and it must be possible to create Message and provide MsgType directly...
Or maybe I don't understand correctly the FIX message standard and fields I have to provide?
Regards,
Alex

Instead of creating a message from scratch, you should be using the predefined messages in QuickFIX/J.
In your case I would start looking at quickfix.fix44.NewOrderList.
By using this class, a whole lot of fields will be filled in for you in the header and footer part of the message (BeginString, BodyLength, MsgType, CheckSum, ...). You then only need to concern yourself mostly with the main part (ie body) of the message.
For the repeating group, there are helper classes available to set that information in the message. E.g. for NewOrderList.NoOrders:
quickfix.fix44.NewOrderList fixMessage = new quickfix.fix44.NewOrderList (
.... // check constructor for what parameters to pass
);
// ...
quickfix.fix44.NewOrderList.NoOrders noOrders = new quickfix.fix44.NewOrderList.NoOrders();
// ...
fixMessage.addGroup( noOrders );

Ok I've got it.
I've used generic group, and set Field manually.
So updated code solution is:
Message message = new Message();
Header header = message.getHeader();
header.setField(new BeginString("FIX.4.4"));
header.setField(new MsgType("E"));
header.setField(new SenderCompID("it's me"));
header.setField(new TargetCompID("my counterparty"));
message.setField(new ListID(_fixListId));
message.setField(new TotNoOrders(_list.size()));
message.setField(new NoOrders(_list.size()));
int idx = 0;
for (Order order : _list) {
Group group = new Group(18, new ClOrdID().getTag()); //18 is the number of field I will add below inot the group, second paramaeter is the first field of the group
group.setField(new ClOrdID(order.getId()));
group.setField(new ListSeqNo(++idx));
//message.setField(.... other fields to add to describe my order)
message.addGroup(group);
}

Related

Need assistance with a Google Sheet and an auto email function

I have a very simple need and I think a script will be able to do this. I have a order tracking sheet with many rows of data and in column Q my team is supposed to enter a date of acknowledgement. Well, at times this process gets overlooked.
I would like to have a script which checks to see which cells in Q are blank, and send me (and my team) a list of the empty cells, but refer to them with labels from the data in A , B , C & D and make a reference to the entry date which is in column P. This way, I am not hunting for cells, but the script is sending me an email of a list which is easy to read.
The email only has to say something like :
"The following orders have not yet been acknowledged:
TextfromA, TextfromB, TextfromC, TextfromD sent to vendor on DatefromP
TextfromA, TextfromB, TextfromC, TextfromD sent to vendor on DatefromP
TextfromA, TextfromB, TextfromC, TextfromD sent to vendor on DatefromP
etc....
Once the Q cell is populated, it should be ignored by the script. I would like the script to email me and the team this current list every 72 hours. Also, if at all possible I would like to ignore certain rows (which are like headers). If we can't, that's fine.
I know it's probably very simple, but I do need some help!!
Thanks in advance!
Here's a hint to get you started:
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('tracking sheet');
var rg=sh.getDataRange();
var dataA=rg.getValues();
var message=''
for(var i=0;i<dataA.length;i++){
if(!dataA[i][16]){
message+=dataA[i][0] + ', ' + dataA[i][1] + ', ' + dataA[i][2] + ', ' + dataA[i][3] + '\n';
}
}
if(message.length>0){
//Send Emails
}

Getting the total number of records in PagedList

The datagrid that I use on the client is based on SQL row number; it also requires a total number of pages for its paging. I also use the PagedList on the server.
SQL Profiler shows that the PagedList makes 2 db calls - the first to get the total number of records and the second to get the current page. The thing is that I can't find a way to extract that total number of records from the PagedList. Therefore, currently I have to make an extra call to get that total which creates 3 calls in total for each request, 2 of which are absolutely identical. I understand that I probably won't be able to rid of the call to get the totals but I hate to call it twice. Here is an extract from my code, I'd really appreciate any help in this:
var t = from c in myDb.MyTypes.Filter<MyType>(filterXml) select c;
response.Total = t.Count(); // my first call to get the total
double d = uiRowNumber / uiRecordsPerPage;
int page = (int)Math.Ceiling(d) + 1;
var q = from c in myDb.MyTypes.Filter<MyType>(filterXml).OrderBy(someOrderString)
select new ReturnType
{
Something = c.Something
};
response.Items = q.ToPagedList(page, uiRecordsPerPage);
PagedList has a .TotalItemCount property which reflects the total number of records in the set (not the number in a particular page). Thus response.Items.TotalItemCount should do the trick.

Crystal Report Counting

My question is similar to the link.
Crystal Reports - Count Formula
The answer only works when the certain status type is giving to you.
Now I am wondering that what if the status type is not giving to you (You dont know what's inside this filed first), and the type of the status can be varied based what's in {statustype} field.
And I want to be able to list all distinct status type and calculate it's total appearance in the report.
Well its easy if you see it my way, I read that thread which you referenced.
Make different Formulas for all the status types that you may know of, I am pretty sure that they will be maximum 4 or 5. Make formula like
localvar int x;
if(statustype = 'Accepted')
(
x = x++;
)
x;
Or you can put all the formulas to one, using the same if clause but changing the display string, make sure that its a summary field or is placed at the report footer.
localvar int accept;
localvar int reject;
localvar int Pending;
if(statustype = 'Accepted')
(
accept= accept++;
)
else if
(
reject = reject ++;
)
else if
(
Pending = Pending++;
);
"Accepted "+ accept + " Rejected " + reject + " Pending "+ Pending;
Hope this helps,
I figured out that a easy way that we can create a placeholder in main report for subreport. And we can make the manipulation in the subreport

Calculation of Previous field

New to CR and use CR v10 and SQL Server 2000.
For the first record i.e Beginning Balance , the calculation is sum(field) from the input date, which I have calculated in SP as BegDateSum
But for the rest of the records under a group, the calculation should be previous(balance)+IN+OUT
Sample has been given:
Date Doc Descrip IN OUT Balance
Group Header-------- Beginning Balance-------------- 50 <---- sum(field) from my inputdate
3/2/2012 A -1 0 49 <-- (50+(-1)+0)
4/2/2012 B -2 0 47 <-- (49+(-2)+0)
5/2/2012 C 0 3 50
6/2/2012 D -2 3 51
How do I achieve this?
I am not sure whether to use running total, in case I have to how to do it.
A running total field won't work in this case, they are designed to add up (or count, or average, etc) one field and give you the sub-totals automatically. But, we can do some custom functions that will give the results you need. Assuming that your initial 50 is a static value, you would set a variable to that amount, and then add the IN and OUT values as you go along (printing that result of that).
First, initialize the value in the report header with a formula like:
WhilePrintingRecords;
Global NumberVar Balance;
Balance := 50;
""; //print nothing on the screen
Then, the formula to calculate and show the new balance, in the bar where the data is:
WhilePrintingRecords;
Global NumberVar Balance;
Balance := Balance + {tableName.IN} + {tableName.OUT};
The last line both calculates the new value, and tells what the result of the formula should be.
If the "50" is calculated somehow, then that will have to be done before the formula that calculates the new balance. If it is based off of the first record read in, you'll want to use a formula that includes If PreviousIsNull({tableName.Balance}) Then ..., that is usually a good indicator of the first record in the data set (unless that field can be null).

Issues using retract in then condition of a rule

I am trying to write a rule to detect if a given event has occurred for 'n' number times in last 'm' duration of time.
I am using drools version 5.4.Final. I have also tried 5.5.Final with no effect.
I have found that there are a couple of Conditional Elements, as Drools call it, accumulate and collect. I have used collect in my sample rule below
rule "check-login-attack-rule-1"
dialect "java"
when
$logMessage: LogMessage()
$logMessages : ArrayList ( size >= 3 )
from collect(LogMessage(getAction().equals(Action.Login)
&& isProcessed() == false)
over window:time(10s))
then
LogManager.debug(Poc.class, "!!!!! Login Attack detected. Generating alert.!!!"+$logMessages.size());
LogManager.debug(Poc.class, "Current Log Message: "+$logMessage.getEventName()+":"+(new Date($logMessage.getTime())));
int size = $logMessages.size();
for(int i = 0 ; i < size; i++) {
Object msgObj = $logMessages.get(i);
LogMessage msg = (LogMessage) msgObj;
LogManager.debug(Poc.class, "LogMessage: "+msg.getEventName()+":"+(new Date(msg.getTime())));
msg.setProcessed(true);
update(msgObj); // Does not work. Rule execution does not proceed beyond this point.
// retract(msgObj) // Does not work. Rule execution does not proceed beyond this point.
}
// Completed processing the logs over a given window. Now removing the processed logs.
//retract($logMessages) // Does not work. Rule execution does not proceed beyond this point.
end
The code to inject logs is as below. The code injects logs at every 3 secs and fires rules.
final StatefulKnowledgeSession kSession = kBase.newStatefulKnowledgeSession();
long msgId = 0;
while(true) {
// Generate Log messages every 3 Secs.
// Every alternate log message will satisfy a rule condition
LogMessage log = null;
log = new LogMessage();
log.setEventName("msg:"+msgId);
log.setAction(LogMessage.Action.Login);
LogManager.debug(Poc.class, "PUSHING LOG: "+log.getEventName()+":"+log.getTime());
kSession.insert(log);
kSession.fireAllRules();
LogManager.debug(Poc.class, "PUSHED LOG: "+log.getEventName()+":"+(new Date(log.getTime())));
// Sleep for 3 secs
try {
sleep(3*1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
msgId++;
}
With this, what I could achieve is checking for existence of the above said LogMessage in last 10 secs. I could also find out the exact set of LogMessages which occurred in last 10 secs triggering the rule.
The problem is, once these messages are processed, they should not take part in next cycle of evaluation. This is something which I've not be able to achieve. I'll explain this with example.
Consider a timeline below, The timeline shows insertion of log messages and the state of alert generation which should happen.
Expected Result
Secs -- Log -- Alert
0 -- LogMessage1 -- No Alert
3 -- LogMessage2 -- No Alert
6 -- LogMessage3 -- Alert1 (LogMessage1, LogMessage2, LogMessage3)
9 -- LogMessage4 -- No Alert
12 -- LogMessage5 -- No Alert
15 -- LogMessage6 -- Alert2 (LogMessage4, LogMessage5, LogMessage6)
But whats happening with current code is
Actual Result
Secs -- Log -- Alert
0 -- LogMessage1 -- No Alert
3 -- LogMessage2 -- No Alert
6 -- LogMessage3 -- Alert1 (LogMessage1, LogMessage2, LogMessage3)
9 -- LogMessage4 -- Alert2 (LogMessage2, LogMessage3, LogMessage4)
12 -- LogMessage5 -- Alert3 (LogMessage3, LogMessage4, LogMessage5)
15 -- LogMessage6 -- Alert4 (LogMessage4, LogMessage5, LogMessage6)
Essentially, I am not able to discard the messages which are already processed and have taken part in an alert generation. I tried to use retract to remove the processed facts from its working memory. But when I added retract in the then part of the rule, the rules stopped firing at all. I have not been able to figure out why the rules stop firing after adding the retract.
Kindly let me know where am I going wrong.
You seem to be forgetting to set as processed the other 3 facts in the list. You would need a helper class as a global to do so because it should be done in a for loop. Otherwise, these groups of messages can trigger the rule as well:
1 no triggering
1,2 no triggerning
1,2,3 triggers
2,3,4 triggers because a new fact is added and 2 and 3 were in the list
3,4,5 triggers because a new fact is added and 3 and 4 were in the list
and so on
hope this helps